package com.ssy.lingxi.order.serviceimpl.web;

import cn.hutool.core.date.DateUtil;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ssy.lingxi.common.constant.member.RoleTypeEnum;
import com.ssy.lingxi.common.constant.order.OrderTypeEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.api.model.vo.inner.request.MemberFeignPayProviderVO;
import com.ssy.lingxi.order.entity.*;
import com.ssy.lingxi.order.model.bo.DeliveryPlanDayBO;
import com.ssy.lingxi.order.model.constant.*;
import com.ssy.lingxi.order.model.vo.basic.request.*;
import com.ssy.lingxi.order.model.vo.basic.response.*;
import com.ssy.lingxi.order.model.vo.common.request.LogisticsAddressVO;
import com.ssy.lingxi.order.repository.*;
import com.ssy.lingxi.order.service.base.IBaseCacheService;
import com.ssy.lingxi.order.service.base.IBaseDeliveryHistoryService;
import com.ssy.lingxi.order.service.web.IDeliveryPlanService;
import com.ssy.lingxi.workflow.api.feign.ProcessFeign;
import com.ssy.lingxi.workflow.api.model.contant.ProcessEnum;
import com.ssy.lingxi.workflow.api.model.contant.ProcessTaskStatusEnum;
import com.ssy.lingxi.workflow.api.model.vo.request.TaskExecuteVO;
import com.ssy.lingxi.workflow.api.model.vo.request.TaskStartVO;
import com.ssy.lingxi.workflow.api.model.vo.response.SimpleTaskCompleteVO;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;


/**
 * 送货计划,送货通知单相关接口
 * @author czh
 * @version 2.0.0
 */
@Service
public class DeliveryPlanServiceImpl implements IDeliveryPlanService {
    private final static Logger logger = LoggerFactory.getLogger(DeliveryPlanServiceImpl.class);
    @Resource
    private IBaseCacheService baseCacheService;

    @Resource
    private JPAQueryFactory jpaQueryFactory;

    @Resource
    private DeliveryNoticeOrderRepository noticeOrderRepository;

    @Resource
    private DeliveryNoticeProductRepository noticeProductRepository;

    @Resource
    private DeliveryPlanProductRepository planProductRepository;

    @Resource
    private DeliveryPlanOrderRepository planOrderRepository;

    @Resource
    private DeliveryPlanRepository planRepository;

    @Resource
    private IBaseDeliveryHistoryService historyService;

    @Resource
    private OrderProductRepository orderProductRepository;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private DeliveryOuterHistoryRepository deliveryOuterHistoryRepository;

    @Resource
    private OrderRepository orderRepository;

    @Resource
    private ProcessFeign taskExecuteControllerFeign;

    @Resource
    private DeliveryOrderProductRepository deliveryOrderProductRepository;

    /**
     * 送货计划-创建送货计划
     * @param headers Http头部信息
     * @param param 接口参数
     * @return 查询结果
     */
    @Transactional
    @Override
    public Wrapper<Void> createDeliveryPlan(HttpHeaders headers, DeliveryPlanCreateVO param,Integer type) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        DeliveryPlanDO deliveryPlanDO = new DeliveryPlanDO();
        deliveryPlanDO.setDigest(param.getDigest());
        deliveryPlanDO.setPlanNo(createOrderSn(BaseDeliveryEnum.DELIVERY_PLAN_SERIAL_NO.getName()));
        LocalDateTime planStartTime = LocalDateTime.parse(param.getPlanStartTime().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER);
        //校验当前所选时间段
        if(verifyCreateTime(planStartTime)){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_START_TIME_ERROR);
        }
        //校验当前所选会员时间段内是否创建过送货计划
        if(verifyPlan(loginUser,param)){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_CREATE_ONLY_ERROR);
        }
        deliveryPlanDO.setPlanStartTime(planStartTime);
        deliveryPlanDO.setPlanEndTime(LocalDateTime.parse(param.getPlanEndTime().concat(" 23:59:59"), OrderServiceContants.DEFAULT_TIME_FORMATTER));
        deliveryPlanDO.setBuyerMemberId(loginUser.getMemberId());
        deliveryPlanDO.setBuyerRoleId(loginUser.getMemberRoleId());
        deliveryPlanDO.setBuyerMemberName(loginUser.getUserName());
        deliveryPlanDO.setVendorMemberId(param.getVendorMemberId());
        deliveryPlanDO.setVendorRoleId(param.getVendorRoleId());
        deliveryPlanDO.setVendorMemberName(param.getVendorMemberName());
        deliveryPlanDO.setOuterStatus(DeliveryOuterStatusEnum.WAIT_CONFIRM.getCode());
        deliveryPlanDO.setStatus(DeliveryPlanStatusEnum.WAIT_SUBMIT.getCode());
        deliveryPlanDO.setCreateTime(LocalDateTime.now());
        deliveryPlanDO.setType(type);
        planRepository.save(deliveryPlanDO);
        //执行送货计划外部状态工作流
        Wrapper<SimpleTaskCompleteVO> taskResult = startWork(loginUser,deliveryPlanDO.getId(), ProcessEnum.ORDER_DELIVERY_PLAN.getProcessKey());
        if (ResponseCode.SUCCESS.getCode() != taskResult.getCode()) {
            throw new RuntimeException(taskResult.getMessage());
        }
        deliveryPlanDO.setTaskId(taskResult.getData().getTaskId());
        deliveryPlanDO.setOuterStatus(taskResult.getData().getStatus());
        planRepository.save(deliveryPlanDO);
        List<DeliveryPlanOrderDO> deliveryPlanOrderDOS = new ArrayList<>();
        List<DeliveryPlanProductParamVO> productList = param.getProductList();
        List<DeliveryPlanProductDO> planProducts = productList.stream().map(product -> {
            DeliveryPlanProductDO planProduct = new DeliveryPlanProductDO();
            planProduct.setDeliveryPlan(deliveryPlanDO);
            planProduct.setSkuId(product.getSkuId());
            planProduct.setProductName(product.getProductName());
            planProduct.setType(product.getSpec());
            planProduct.setCategory(product.getCategory());
            planProduct.setBrand(product.getBrand());
            planProduct.setUnit(product.getUnit());
            planProduct.setPurchaseCount(product.getPurchaseCountSum());
            planProduct.setReceiveCount(product.getReceiveCountSum());
            planProduct.setTransitCount(product.getTransitCountSum());
            planProduct.setPlanCount(product.getPlanCountSum());
            planProduct.setLeftCount(product.getLeftCountSum());
            List<DeliveryPlanOrderDO> orders = product.getOrders().stream().map(order -> {
                DeliveryPlanOrderDO deliveryPlanOrderDO = new DeliveryPlanOrderDO();
                deliveryPlanOrderDO.setDeliveryPlanProduct(planProduct);
                deliveryPlanOrderDO.setPlanId(deliveryPlanDO.getId());
                deliveryPlanOrderDO.setSkuId(planProduct.getSkuId());
                deliveryPlanOrderDO.setOrderNo(order.getOrderNo());
                deliveryPlanOrderDO.setOrderDigest(order.getOrderDigest());
                deliveryPlanOrderDO.setOrderProductId(order.getOrderProductId());
                deliveryPlanOrderDO.setCreateTime(order.getCreateTime());
                deliveryPlanOrderDO.setPurchaseCount(order.getPurchaseCount());
                deliveryPlanOrderDO.setReceiveCount(order.getReceiveCount());
                deliveryPlanOrderDO.setTransitCount(order.getTransitCount());
                deliveryPlanOrderDO.setLeftCount(order.getLeftCount());
                deliveryPlanOrderDO.setPlanCount(order.getPlanCount());
                deliveryPlanOrderDO.setConsigneeId(order.getConsigneeId());
                deliveryPlanOrderDO.setConsignee(order.getConsignee());
                deliveryPlanOrderDO.setProvinceName(order.getProvinceName());
                deliveryPlanOrderDO.setCityName(order.getCityName());
                deliveryPlanOrderDO.setDistrictName(order.getDistrictName());
                deliveryPlanOrderDO.setStreetName(order.getStreetName());
                deliveryPlanOrderDO.setAddress(order.getAddress());
                deliveryPlanOrderDO.setPhone(order.getPhone());
                deliveryPlanOrderDO.setPlanDays(order.getPlanDays());
                return deliveryPlanOrderDO;
            }).collect(Collectors.toList());
            deliveryPlanOrderDOS.addAll(orders);
            planProduct.setDeliveryPlanOrders(new HashSet<>(orders));
            return planProduct;
        }).collect(Collectors.toList());
        //保存送货计划物料信息
        planProductRepository.saveAll(planProducts);
        planOrderRepository.saveAll(deliveryPlanOrderDOS);
        //保存外部单据流转记录
        historyService.saveBuyerOuterHistory(loginUser.getMemberId(),loginUser.getMemberRoleId(),loginUser.getUserName(), loginUser.getUserOrgName(),loginUser.getMemberRoleName(),deliveryPlanDO.getId(),deliveryPlanDO.getPlanNo(), DeliveryOperationEnum.CREATE_DELIVERY_PLAN,deliveryPlanDO.getOuterStatus(),param.getRemark(), DeliveryHistoryTypeEnum.DELIVERY_PLAN.getCode());
        return Wrapper.success();
    }

    /**
     * 送货计划-修改送货计划
     * @param headers Http头部信息
     * @param param 接口参数
     * @return 操作结果
     */
    @Transactional
    @Override
    public Wrapper<Void> updateDeliveryPlan(HttpHeaders headers, DeliveryPlanUpdateVO param) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        DeliveryPlanDO deliveryPlanDO = planRepository.findById(param.getPlanId()).orElse(null);
        if(Objects.isNull(deliveryPlanDO)){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_DOES_NOT_EXIST);
        }
        //非待提交、待修订，已确认的送货计划不允许修改
        if(!deliveryPlanDO.getStatus().equals(DeliveryPlanStatusEnum.ALREADY_CONFIRM.getCode()) && !deliveryPlanDO.getStatus().equals(DeliveryPlanStatusEnum.WAIT_SUBMIT.getCode()) && !deliveryPlanDO.getStatus().equals(DeliveryPlanStatusEnum.WAIT_MODIFY.getCode())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_UPDATE_STATUS_ERROR);
        }
        deliveryPlanDO.setDigest(param.getDigest());
        deliveryPlanDO.setUpdateTime(LocalDateTime.now());
        //修改送货计划执行新的送货计划外部状态工作流
        Wrapper<SimpleTaskCompleteVO> taskResult = startWork(loginUser,deliveryPlanDO.getId(), ProcessEnum.ORDER_DELIVERY_PLAN.getProcessKey());
        if (ResponseCode.SUCCESS.getCode() != taskResult.getCode()) {
            return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
        }
        deliveryPlanDO.setTaskId(taskResult.getData().getTaskId());
        deliveryPlanDO.setOuterStatus(taskResult.getData().getStatus());
        deliveryPlanDO.setStatus(DeliveryPlanStatusEnum.WAIT_SUBMIT.getCode());
        planRepository.save(deliveryPlanDO);
        List<DeliveryPlanOrderQueryVO> orders = param.getOrders();
        List<Long> planOrderIdList = orders.stream().map(DeliveryPlanOrderQueryVO::getPlanOrderId).collect(Collectors.toList());
        Map<Long, DeliveryPlanOrderDO> deliveryPlanOrderMap = planOrderRepository.findAllById(planOrderIdList).stream().collect(Collectors.toMap(DeliveryPlanOrderDO::getId, DeliveryPlanOrderDO -> DeliveryPlanOrderDO));
        List<DeliveryPlanOrderDO> deliveryPlanOrderList = orders.stream().map(order -> {
            DeliveryPlanOrderDO deliveryPlanOrderDO = deliveryPlanOrderMap.get(order.getPlanOrderId());
            if(Objects.isNull(deliveryPlanOrderDO)){
                throw new RuntimeException(ResponseCode.ORDER_DELIVERY_PLAN_DOES_NOT_EXIST.getMessage());
            }
            deliveryPlanOrderDO.setPlanDays(order.getPlanDays());
            deliveryPlanOrderDO.setPlanCount(order.getPlanCount());
            return deliveryPlanOrderDO;
        }).collect(Collectors.toList());
        planOrderRepository.saveAll(deliveryPlanOrderList);
        //保存外部流转记录
        historyService.saveBuyerOuterHistory(loginUser.getMemberId(),loginUser.getMemberRoleId(),loginUser.getUserName(), loginUser.getUserOrgName(),loginUser.getMemberRoleName(),deliveryPlanDO.getId(),deliveryPlanDO.getPlanNo(), DeliveryOperationEnum.MODIFY_DELIVERY_PLAN,deliveryPlanDO.getOuterStatus(),param.getRemark(), DeliveryHistoryTypeEnum.DELIVERY_PLAN.getCode());
        return Wrapper.success();
    }

    /**
     * 送货计划-删除送货计划
     * @param headers Http头部信息
     * @param param 接口参数
     * @return 操作结果
     */
    @Transactional
    @Override
    public Wrapper<Void> deleteDeliveryPlan(HttpHeaders headers, IdVO param) {
        DeliveryPlanDO deliveryPlanDO = planRepository.findById(param.getId()).orElse(null);
        if(Objects.isNull(deliveryPlanDO)){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_DOES_NOT_EXIST);
        }
        //判断当前状态是否可以删除
        if(!deliveryPlanDO.getStatus().equals(DeliveryPlanStatusEnum.WAIT_SUBMIT.getCode())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_DELETE_STATUS_ERROR);
        }
        List<DeliveryOuterHistoryDO> historyList = deliveryOuterHistoryRepository.findByOrderIdAndDeliveryHistoryType(deliveryPlanDO.getId(), DeliveryHistoryTypeEnum.DELIVERY_PLAN.getCode(), Sort.by("id").descending());
        //判断外部流转记录里是否有除待提交外的状态，如果有则无法删除
        if(!historyList.stream().allMatch( h -> h.getStatus().equals(DeliveryHistoryStatusEnum.WAIT_SUBMIT.getCode()))){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_DELETE_STATUS_ERROR);
        }
        planOrderRepository.deleteByPlanId(deliveryPlanDO.getId());
        planProductRepository.deleteByDeliveryPlan(deliveryPlanDO);
        planRepository.delete(deliveryPlanDO);
        return Wrapper.success();
    }

    /**
     * 送货计划-生成通知单所需数据
     * @param headers Http头部信息
     * @param param 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<NoticeOrderParamByPlanVO> NoticeOrderByPlanCreate(HttpHeaders headers, NoticeOrderByPlanCreateVO param) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        LocalDateTime deliveryTime = LocalDateTime.parse(param.getTime().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER);
        if(verifyCreateTime(deliveryTime)){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_NOTICE_CREATE_TIME_ERROR);
        }
        DeliveryPlanDO deliveryPlan = planRepository.findById(param.getPlanId()).orElse(null);
        if(Objects.isNull(deliveryPlan) || !deliveryPlan.getVendorMemberId().equals(loginUser.getMemberId()) || !deliveryPlan.getVendorRoleId().equals(loginUser.getMemberRoleId())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_DOES_NOT_EXIST);
        }
        if(!deliveryPlan.getStatus().equals(DeliveryPlanStatusEnum.ALREADY_CONFIRM.getCode())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_CREATE_NOTICE_STATUS_ERROR);
        }
        List<Long> planOrderIds = param.getPlanOrderIds();
        List<DeliveryPlanOrderDO> planOrder = planOrderRepository.findAllById(planOrderIds);
        if(planOrder.size() == 0){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_ORDER_EXIST_ERROR);
        }
        if(noticeOrderRepository.countByNoticeNoAndDeliveryTimeAndStatusNot(deliveryPlan.getPlanNo(),deliveryTime,DeliveryNoticeOrderStatusEnum.INVALID.getCode()) > 0){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_CREATE_DELIVERY_CREATE_STATUS_ERROR);
        }

        //获取第一个订单的地址信息
        DeliveryPlanOrderDO deliveryPlanOrder = planOrder.get(0);
        NoticeOrderParamByPlanVO order = new NoticeOrderParamByPlanVO();
        order.setBuyerMemberId(deliveryPlan.getBuyerMemberId());
        order.setPlanNo(deliveryPlan.getPlanNo());
        order.setBuyerRoleId(deliveryPlan.getBuyerRoleId());
        order.setBuyerMemberName(deliveryPlan.getBuyerMemberName());
        order.setDigest(deliveryPlan.getDigest());
        order.setDeliveryTime(param.getTime());
        order.setDeliveryStartTime(BaseDeliveryEnum.DEFAULT_START_TIME.getName());
        order.setDeliveryEndTime(BaseDeliveryEnum.DEFAULT_END_TIME.getName());
        order.setConsignee(deliveryPlanOrder.getConsignee());
        order.setProvinceName(deliveryPlanOrder.getProvinceName());
        order.setCityName(deliveryPlanOrder.getCityName());
        order.setDistrictName(deliveryPlanOrder.getDistrictName());
        order.setStreetName(deliveryPlanOrder.getStreetName());
        order.setAddress(deliveryPlanOrder.getAddress());
        order.setConsigneeId(deliveryPlanOrder.getConsigneeId());
        order.setPhone(deliveryPlanOrder.getPhone());
        String day = deliveryTime.format(DateTimeFormatter.ofPattern("MM-dd"));
        List<NoticeProductParamVO> deliveryNoticeProducts = planOrder.stream().map(product -> {
            NoticeProductParamVO deliveryNoticeProductDO = new NoticeProductParamVO();
            DeliveryPlanProductDO deliveryPlanProduct = product.getDeliveryPlanProduct();
            deliveryNoticeProductDO.setSkuId(product.getSkuId());
            deliveryNoticeProductDO.setOrderProductId(product.getOrderProductId());
            deliveryNoticeProductDO.setProductName(deliveryPlanProduct.getProductName());
            deliveryNoticeProductDO.setPlanOrderId(product.getId());
            deliveryNoticeProductDO.setType(deliveryPlanProduct.getType());
            deliveryNoticeProductDO.setCategory(deliveryPlanProduct.getCategory());
            deliveryNoticeProductDO.setBrand(deliveryPlanProduct.getBrand());
            deliveryNoticeProductDO.setUnit(deliveryPlanProduct.getUnit());
            deliveryNoticeProductDO.setOrderNo(product.getOrderNo());
            deliveryNoticeProductDO.setOrderProductId(product.getOrderProductId());
            deliveryNoticeProductDO.setCreateTime(product.getCreateTime());
            deliveryNoticeProductDO.setPurchaseCount(product.getPurchaseCount());
            DeliveryPlanDayBO deliveryPlanDayBO = product.getPlanDays().stream().filter(planDay -> planDay.getDay().equals(day)).findFirst().orElse(null);
            deliveryNoticeProductDO.setPlanCount(Objects.isNull(deliveryPlanDayBO) ? BigDecimal.ZERO : deliveryPlanDayBO.getPlanCount());
            return deliveryNoticeProductDO;
            //过滤通知数量为0的订单
        }).filter( p -> !BigDecimal.ZERO.equals(p.getPlanCount())).collect(Collectors.toList());
        order.setProducts(deliveryNoticeProducts);
        return Wrapper.success(order);
    }

    /**
     * 送货计划-生成送货单所需数据
     * @param headers Http头部信息
     * @param param 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<DeliveryOrderCreateByPlanVO> DeliveryOrderByPlanCreate(HttpHeaders headers, DeliveryOrderByPlanCreateVO param) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        LocalDateTime deliveryTime = LocalDateTime.parse(param.getTime().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER);
        if(verifyCreateTime(deliveryTime)){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_ORDER_CREATE_TIME_ERROR);
        }
        DeliveryPlanDO deliveryPlan = planRepository.findById(param.getPlanId()).orElse(null);
        if(Objects.isNull(deliveryPlan) || !deliveryPlan.getVendorMemberId().equals(loginUser.getMemberId()) || !deliveryPlan.getVendorRoleId().equals(loginUser.getMemberRoleId())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_DOES_NOT_EXIST);
        }
        if(!deliveryPlan.getStatus().equals(DeliveryPlanStatusEnum.ALREADY_CONFIRM.getCode())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_CREATE_NOTICE_STATUS_ERROR);
        }
        List<Long> planOrderIds = param.getPlanOrderIds();
        List<DeliveryPlanOrderDO> planOrder = planOrderRepository.findAllById(planOrderIds);
        if(planOrder.size() == 0){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_ORDER_EXIST_ERROR);
        }
        String day = deliveryTime.format(DateTimeFormatter.ofPattern("MM-dd"));
        //获取第一个订单的送货信息
        DeliveryOrderCreateByPlanVO deliveryOrderCreateVO = new DeliveryOrderCreateByPlanVO();
        deliveryOrderCreateVO.setSourceType(1);
        deliveryOrderCreateVO.setSourceNo(deliveryPlan.getPlanNo());
        deliveryOrderCreateVO.setBuyerMemberId(deliveryPlan.getBuyerMemberId());
        deliveryOrderCreateVO.setBuyerRoleId(deliveryPlan.getBuyerRoleId());
        deliveryOrderCreateVO.setBuyerMemberName(deliveryPlan.getBuyerMemberName());
        deliveryOrderCreateVO.setDeliveryTime(deliveryTime.format(OrderServiceContants.DEFAULT_DATE_FORMATTER));
        //获取第一个送货物料
        DeliveryPlanProductDO deliveryPlanProductDO = deliveryPlan.getDeliveryPlanProducts().stream().findFirst().orElse(null);
        deliveryOrderCreateVO.setDigest(deliveryOrderCreateVO.getDeliveryTime().concat(deliveryPlanProductDO.getProductName().concat(BaseDeliveryEnum.RECEIVE_ORDER_CN.getName())));
        deliveryOrderCreateVO.setDeliveryStartTime(BaseDeliveryEnum.DEFAULT_START_TIME.getName());
        deliveryOrderCreateVO.setDeliveryEndTime(BaseDeliveryEnum.DEFAULT_END_TIME.getName());
        List<DeliveryOrderProductParamVO> DeliveryOrderProductParams;
        DeliveryOrderProductParams = planOrder.stream().map(p -> {
            DeliveryOrderProductParamVO deliveryOrderProductParamVO = new DeliveryOrderProductParamVO();
            deliveryOrderProductParamVO.setSkuId(p.getSkuId());
            DeliveryPlanProductDO deliveryPlanProduct = p.getDeliveryPlanProduct();
            deliveryOrderProductParamVO.setProductName(deliveryPlanProduct.getProductName());
            deliveryOrderProductParamVO.setSpec(deliveryPlanProduct.getType());
            deliveryOrderProductParamVO.setCategory(deliveryPlanProduct.getCategory());
            deliveryOrderProductParamVO.setBrand(deliveryPlanProduct.getBrand());
            deliveryOrderProductParamVO.setUnit(deliveryPlanProduct.getUnit());
            deliveryOrderProductParamVO.setOrderNo(p.getOrderNo());
            deliveryOrderProductParamVO.setOrderProductId(p.getOrderProductId());
            deliveryOrderProductParamVO.setCreateTime(p.getCreateTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            deliveryOrderProductParamVO.setPurchaseCount(p.getPurchaseCount());
            //缺少送货数量校验
            DeliveryPlanDayBO deliveryPlanDayBO = p.getPlanDays().stream().filter(planDay -> planDay.getDay().equals(day)).findFirst().orElse(null);
            deliveryOrderProductParamVO.setDeliveryCount(Objects.isNull(deliveryPlanDayBO) ? BigDecimal.ZERO : deliveryPlanDayBO.getPlanCount());
            return deliveryOrderProductParamVO;
            //过滤送货数量为0的订单
        }).filter( p -> !BigDecimal.ZERO.equals(p.getDeliveryCount())).collect(Collectors.toList());
        deliveryOrderCreateVO.setProducts(DeliveryOrderProductParams);
        DeliveryPlanOrderDO deliveryPlanOrder = planOrder.get(0);
        //收发货人地址信息
        LogisticsAddressVO logisticsAddressVO = new LogisticsAddressVO();
        logisticsAddressVO.setConsignee(deliveryPlanOrder.getConsignee());
        logisticsAddressVO.setProvinceName(deliveryPlanOrder.getProvinceName());
        logisticsAddressVO.setCityName(deliveryPlanOrder.getCityName());
        logisticsAddressVO.setDistrictName(deliveryPlanOrder.getDistrictName());
        logisticsAddressVO.setStreetName(deliveryPlanOrder.getStreetName());
        logisticsAddressVO.setAddress(deliveryPlanOrder.getAddress());
        logisticsAddressVO.setPhone(deliveryPlanOrder.getPhone());
        deliveryOrderCreateVO.setReceiveVO(logisticsAddressVO);
        return Wrapper.success(deliveryOrderCreateVO);
    }

    /**
     * 送貨通知單-生成送货单所需数据
     * @param headers Http头部信息
     * @param idVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<DeliveryOrderCreateByPlanVO> DeliveryOrderByNoticeCreate(HttpHeaders headers, IdVO idVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        DeliveryNoticeOrderDO noticeOrder = noticeOrderRepository.findById(idVO.getId()).orElse(null);
        if(Objects.isNull(noticeOrder) || !noticeOrder.getVendorMemberId().equals(loginUser.getMemberId()) || !noticeOrder.getVendorRoleId().equals(loginUser.getMemberRoleId())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_NOTICE_ORDER_DOES_NOT_EXIST);
        }
        if(!noticeOrder.getStatus().equals(DeliveryNoticeOrderStatusEnum.ALREADY_CONFIRM.getCode())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_CREATE_DELIVERY_STATUS_ERROR);
        }
        Set<DeliveryNoticeProductDO> deliveryNoticeProducts = noticeOrder.getDeliveryNoticeProducts();
        List<String> orderNos = deliveryNoticeProducts.stream().map(DeliveryNoticeProductDO::getOrderNo).collect(Collectors.toList());
        List<OrderDO> byOrderNoIn = orderRepository.findByOrderNoIn(orderNos);
        //
        if(!byOrderNoIn.stream().allMatch(orderDO -> orderDO.getOuterStatus().equals(OrderOuterStatusEnum.TO_CONFIRM_DELIVERY.getCode()))){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_CREATE_DELIVERY_STATUS_ERROR);
        }
        //获取第一个订单的送货信息
        DeliveryOrderCreateByPlanVO deliveryOrderCreateVO = new DeliveryOrderCreateByPlanVO();
        deliveryOrderCreateVO.setSourceType(2);
        deliveryOrderCreateVO.setSourceNo(noticeOrder.getNoticeNo());
        deliveryOrderCreateVO.setBuyerMemberId(noticeOrder.getBuyerMemberId());
        deliveryOrderCreateVO.setBuyerRoleId(noticeOrder.getBuyerRoleId());
        deliveryOrderCreateVO.setBuyerMemberName(noticeOrder.getBuyerMemberName());
        deliveryOrderCreateVO.setDeliveryTime(noticeOrder.getDeliveryTime().format(OrderServiceContants.DEFAULT_DATE_FORMATTER));
        deliveryOrderCreateVO.setDigest(noticeOrder.getDigest());
        deliveryOrderCreateVO.setDeliveryStartTime(BaseDeliveryEnum.DEFAULT_START_TIME.getName());
        deliveryOrderCreateVO.setDeliveryEndTime(BaseDeliveryEnum.DEFAULT_END_TIME.getName());
        List<DeliveryOrderProductParamVO> deliveryOrderProducts = deliveryNoticeProducts.stream().map(p -> {
            DeliveryOrderProductParamVO deliveryOrderProductParamVO = new DeliveryOrderProductParamVO();
            deliveryOrderProductParamVO.setSkuId(p.getSkuId());
            deliveryOrderProductParamVO.setProductName(p.getProductName());
            deliveryOrderProductParamVO.setSpec(p.getType());
            deliveryOrderProductParamVO.setCategory(p.getCategory());
            deliveryOrderProductParamVO.setBrand(p.getBrand());
            deliveryOrderProductParamVO.setUnit(p.getUnit());
            deliveryOrderProductParamVO.setOrderNo(p.getOrderNo());
            deliveryOrderProductParamVO.setOrderProductId(p.getOrderProductId());
            deliveryOrderProductParamVO.setCreateTime(p.getCreateTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            deliveryOrderProductParamVO.setPurchaseCount(p.getPurchaseCount());
            deliveryOrderProductParamVO.setDeliveryCount(p.getPlanCount());
            return deliveryOrderProductParamVO;
        }).collect(Collectors.toList());
        deliveryOrderCreateVO.setProducts(deliveryOrderProducts);
        //收发货人地址信息
        LogisticsAddressVO logisticsAddressVO = new LogisticsAddressVO();
        logisticsAddressVO.setConsignee(noticeOrder.getConsignee());
        logisticsAddressVO.setProvinceName(noticeOrder.getProvinceName());
        logisticsAddressVO.setCityName(noticeOrder.getCityName());
        logisticsAddressVO.setDistrictName(noticeOrder.getDistrictName());
        logisticsAddressVO.setStreetName(noticeOrder.getStreetName());
        logisticsAddressVO.setAddress(noticeOrder.getAddress());
        logisticsAddressVO.setPhone(noticeOrder.getPhone());
        deliveryOrderCreateVO.setReceiveVO(logisticsAddressVO);
        deliveryOrderCreateVO.setOrderType(noticeOrder.getType());
        return Wrapper.success(deliveryOrderCreateVO);
    }

    /**
     * 送货计划-查询计划周期内的计划送货物料
     * @param headers  Http头部信息
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<DeliveryPlanProductQueryVO>> pagePlanProducts(HttpHeaders headers, DeliveryPlanProductPageVO pageVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        Integer orderType = pageVO.getOrderType();
        Long buyerMemberId = pageVO.getRoleType().equals(RoleTypeEnum.SERVICE_PROVIDER.getCode()) ? loginUser.getMemberId() : pageVO.getMemberId();
        Long buyerRoleId = pageVO.getRoleType().equals(RoleTypeEnum.SERVICE_PROVIDER.getCode()) ? loginUser.getMemberRoleId() : pageVO.getRoleId();
        Long vendorMemberId = pageVO.getRoleType().equals(RoleTypeEnum.SERVICE_CONSUMER.getCode()) ? loginUser.getMemberId() : pageVO.getMemberId();
        Long vendorRoleId = pageVO.getRoleType().equals(RoleTypeEnum.SERVICE_CONSUMER.getCode()) ? loginUser.getMemberRoleId() : pageVO.getRoleId();
        if(orderType.equals(DeliveryOrderTypeStatusEnum.B2B.getCode())){
            return pagePlanProductsByB2B(pageVO,buyerMemberId,buyerRoleId,vendorMemberId,vendorRoleId);
        }else{
            return pagePlanProductsBySRM(pageVO,buyerMemberId,buyerRoleId,vendorMemberId,vendorRoleId);
        }
    }

    @Override
    public Wrapper<List<DeliveryOuterHistoryVO>> deliveryHistory(HttpHeaders headers, IdVO idVO,Integer code) {
        return Wrapper.success(historyService.listDeliveryOuterHistory(idVO.getId(),code));
    }

    private Wrapper<PageData<DeliveryPlanProductQueryVO>> pagePlanProductsByB2B(DeliveryPlanProductPageVO pageVO,Long buyerMemberId,Long buyerRoleId,Long vendorMemberId,Long vendorRoleId){
        //订单类型枚举集合
        List<Integer> orderTypes = Stream.of(OrderTypeEnum.INQUIRY_TO_PURCHASE.getCode(), OrderTypeEnum.NEED_TO_PURCHASE.getCode(), OrderTypeEnum.SPOT_PURCHASING.getCode(), OrderTypeEnum.COLLECTIVE_PURCHASE.getCode()).collect(Collectors.toList());
        //订单外部状态枚举集合
        List<Integer> orderOuterStatus = Stream.of(OrderOuterStatusEnum.TO_DELIVER.getCode(),OrderOuterStatusEnum.TO_LOGISTICS.getCode(),OrderOuterStatusEnum.TO_CONFIRM_DELIVERY.getCode(),OrderOuterStatusEnum.TO_DEPOSIT.getCode(),OrderOuterStatusEnum.TO_RECEIPT.getCode(),OrderOuterStatusEnum.TO_CONFIRM_RECEIPT.getCode()).collect(Collectors.toList());
        QOrderDO qOrder = QOrderDO.orderDO;
        QOrderProductDO qOrderProduct = QOrderProductDO.orderProductDO;
        QOrderConsigneeDO qOrderConsignee = QOrderConsigneeDO.orderConsigneeDO;
        JPAQuery<DeliveryPlanProductQueryVO> idsQuery = jpaQueryFactory.select(Projections.constructor(DeliveryPlanProductQueryVO.class,qOrderProduct.skuId))
                .from(qOrderProduct)
                .leftJoin(qOrder).on(qOrderProduct.order.id.eq(qOrder.id))
                .where(qOrder.buyerMemberId.eq(buyerMemberId)
                        .and(qOrder.buyerRoleId.eq(buyerRoleId))
                        .and(qOrder.vendorMemberId.eq(vendorMemberId))
                        .and(qOrder.vendorRoleId.eq(vendorRoleId))
                        .and(qOrder.orderType.in(orderTypes))
                        .and(qOrder.outerStatus.in(orderOuterStatus)));
        if(org.springframework.util.StringUtils.hasLength(pageVO.getStartDate()) && org.springframework.util.StringUtils.hasLength(pageVO.getEndDate())) {
            idsQuery.where(qOrder.createTime.after(LocalDateTime.parse(pageVO.getStartDate().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER))
                    .and(qOrder.createTime.before(LocalDateTime.parse(pageVO.getEndDate().concat(" 23:59:59"), OrderServiceContants.DEFAULT_TIME_FORMATTER))));
        }
        idsQuery.groupBy(qOrderProduct.skuId);
        //获取skuId集合，因为skuId并非唯一，还需要将集合再次分组
        List<Long> skuIds = idsQuery.fetch().stream().map(a -> Long.valueOf(a.getSkuId())).collect(Collectors.toList());
        JPAQuery<DeliveryPlanProductQueryVO> query = jpaQueryFactory
                .select(Projections.constructor(DeliveryPlanProductQueryVO.class,qOrderProduct.skuId,qOrderProduct.name,qOrderProduct.category,qOrderProduct.brand,qOrderProduct.unit))
                .from(qOrderProduct)
                .leftJoin(qOrder).on(qOrderProduct.order.id.eq(qOrder.id))
                .where(qOrderProduct.skuId.in(skuIds)
                        .and(qOrder.buyerMemberId.eq(buyerMemberId))
                        .and(qOrder.buyerRoleId.eq(buyerRoleId))
                        .and(qOrder.vendorMemberId.eq(vendorMemberId))
                        .and(qOrder.vendorRoleId.eq(vendorRoleId))
                        .and(qOrder.orderType.in(orderTypes))
                        .and(qOrder.outerStatus.in(orderOuterStatus)));
        if(org.springframework.util.StringUtils.hasLength(pageVO.getStartDate()) && org.springframework.util.StringUtils.hasLength(pageVO.getEndDate())) {
            query.where(qOrder.createTime.after(LocalDateTime.parse(pageVO.getStartDate().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER))
                    .and(qOrder.createTime.before(LocalDateTime.parse(pageVO.getEndDate().concat(" 23:59:59"), OrderServiceContants.DEFAULT_TIME_FORMATTER))));
        }
        query.groupBy(qOrderProduct.skuId,qOrderProduct.name,qOrderProduct.category,qOrderProduct.brand,qOrderProduct.unit);
        List<DeliveryPlanProductQueryVO> planProducts = query.limit(pageVO.getPageSize()).offset(pageVO.getCurrentOffset()).fetch();
        //已排序skuId集合
        List<Long> skuList = planProducts.stream().map(p -> Long.valueOf(p.getSkuId())).collect(Collectors.toList());
        JPAQuery<DeliveryPlanOrderQueryVO> orderQuery = jpaQueryFactory.select(Projections.constructor(DeliveryPlanOrderQueryVO.class,
                qOrder.orderNo, qOrder.digest, qOrder.createTime,
                qOrderProduct.quantity, qOrderProduct.received, qOrderProduct.delivered,
                qOrderConsignee.consigneeId, qOrderConsignee.consignee, qOrderConsignee.provinceName,
                qOrderConsignee.cityName, qOrderConsignee.districtName, qOrderConsignee.streetName,
                qOrderConsignee.address, qOrderConsignee.phone, qOrderProduct.leftCount,
                qOrderProduct.id, qOrderProduct.skuId, qOrderProduct.name,qOrderProduct.noticeCount))
                .from(qOrderProduct)
                .leftJoin(qOrder).on(qOrderProduct.order.id.eq(qOrder.id))
                .leftJoin(qOrderConsignee).on(qOrderProduct.order.id.eq(qOrderConsignee.order.id))
                .where(qOrder.buyerMemberId.eq(buyerMemberId)
                        .and(qOrder.buyerRoleId.eq(buyerRoleId))
                        .and(qOrder.vendorMemberId.eq(vendorMemberId))
                        .and(qOrder.vendorRoleId.eq(vendorRoleId))
                        .and(qOrder.orderType.in(orderTypes))
                        .and(qOrder.outerStatus.in(orderOuterStatus))
                        .and(qOrderProduct.skuId.in(skuList)));

        //拿到所有订单数据
        if(org.springframework.util.StringUtils.hasLength(pageVO.getStartDate()) && org.springframework.util.StringUtils.hasLength(pageVO.getEndDate())) {
            orderQuery.where(qOrder.createTime.after(LocalDateTime.parse(pageVO.getStartDate().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER))
                    .and(qOrder.createTime.before(LocalDateTime.parse(pageVO.getEndDate().concat(" 23:59:59"), OrderServiceContants.DEFAULT_TIME_FORMATTER))));
        }
        orderQuery.groupBy( qOrder.orderNo, qOrder.digest, qOrder.createTime,
                qOrderProduct.quantity, qOrderProduct.received, qOrderProduct.delivered,
                qOrderConsignee.consigneeId, qOrderConsignee.consignee, qOrderConsignee.provinceName,
                qOrderConsignee.cityName, qOrderConsignee.districtName, qOrderConsignee.streetName,
                qOrderConsignee.address, qOrderConsignee.phone, qOrderProduct.leftCount,
                qOrderProduct.id, qOrderProduct.skuId, qOrderProduct.name,qOrderProduct.noticeCount);
        List<DeliveryPlanOrderQueryVO> orders = orderQuery.fetch();
        Integer no = 1;
        for (DeliveryPlanProductQueryVO deliveryPlanProductQueryVO : planProducts) {
            deliveryPlanProductQueryVO.setNo(no);
            no = ++no;
            //根据skuId和商品名称进行归类
            List<DeliveryPlanOrderQueryVO> deliveryPlanOrders = orders.stream().filter(o -> o.getSkuId().equals(deliveryPlanProductQueryVO.getSkuId()) && o.getProductName().equals(deliveryPlanProductQueryVO.getProductName())).collect(Collectors.toList());
            BigDecimal purchaseCount = BigDecimal.ZERO;
            BigDecimal receiveCount = BigDecimal.ZERO;
            BigDecimal transitCount = BigDecimal.ZERO;
            BigDecimal leftCount = BigDecimal.ZERO;
            BigDecimal unplannedCount = BigDecimal.ZERO;
            for (DeliveryPlanOrderQueryVO order : deliveryPlanOrders) {
                purchaseCount = purchaseCount.add(order.getPurchaseCount());
                receiveCount = receiveCount.add(order.getReceiveCount());
                transitCount = transitCount.add(order.getTransitCount());
                leftCount = leftCount.add(order.getLeftCount());
                unplannedCount = unplannedCount.add(order.getUnplannedCount());
            }
            deliveryPlanProductQueryVO.setPurchaseCountSum(purchaseCount);
            deliveryPlanProductQueryVO.setReceiveCountSum(receiveCount);
            deliveryPlanProductQueryVO.setTransitCountSum(transitCount);
            deliveryPlanProductQueryVO.setLeftCountSum(leftCount);
            deliveryPlanProductQueryVO.setPlanCountSum(BigDecimal.ZERO);
            deliveryPlanProductQueryVO.setUnplannedCountSum(unplannedCount);
            deliveryPlanProductQueryVO.setOrders(deliveryPlanOrders);
        }
        long totalCount = query.fetch().size();
        return Wrapper.success(new PageData<>(totalCount, planProducts));
    }

    private Wrapper<PageData<DeliveryPlanProductQueryVO>> pagePlanProductsBySRM(DeliveryPlanProductPageVO pageVO,Long buyerMemberId,Long buyerRoleId,Long vendorMemberId,Long vendorRoleId){
        //订单类型枚举集合
        List<Integer> orderTypes = Stream.of(OrderTypeEnum.QUERY_PRICE_CONTRACT.getCode(), OrderTypeEnum.PRICE_COMPETITION_CONTRACT_PURCHASE.getCode(), OrderTypeEnum.PURCHASE_CONTRACT_BIDDING.getCode(), OrderTypeEnum.REQUISITION_TO_PURCHASE.getCode()).collect(Collectors.toList());
        //订单外部状态枚举集合
        List<Integer> orderOuterStatus = Stream.of(OrderOuterStatusEnum.TO_DELIVER.getCode(),OrderOuterStatusEnum.TO_LOGISTICS.getCode(),OrderOuterStatusEnum.TO_CONFIRM_DELIVERY.getCode(),OrderOuterStatusEnum.TO_DEPOSIT.getCode(),OrderOuterStatusEnum.TO_RECEIPT.getCode(),OrderOuterStatusEnum.TO_CONFIRM_RECEIPT.getCode()).collect(Collectors.toList());
        QOrderDO qOrder = QOrderDO.orderDO;
        QOrderProductDO qOrderProduct = QOrderProductDO.orderProductDO;
        QOrderConsigneeDO qOrderConsignee = QOrderConsigneeDO.orderConsigneeDO;
        JPAQuery<DeliveryPlanProductQueryVO> idsQuery = jpaQueryFactory.select(Projections.constructor(DeliveryPlanProductQueryVO.class,qOrderProduct.productNo))
                .from(qOrderProduct)
                .leftJoin(qOrder).on(qOrderProduct.order.id.eq(qOrder.id))
                .where(qOrder.buyerMemberId.eq(buyerMemberId)
                        .and(qOrder.buyerRoleId.eq(buyerRoleId))
                        .and(qOrder.vendorMemberId.eq(vendorMemberId))
                        .and(qOrder.vendorRoleId.eq(vendorRoleId))
                        .and(qOrder.orderType.in(orderTypes))
                        .and(qOrder.outerStatus.in(orderOuterStatus)));
        if(org.springframework.util.StringUtils.hasLength(pageVO.getStartDate()) && org.springframework.util.StringUtils.hasLength(pageVO.getEndDate())) {
            idsQuery.where(qOrder.createTime.after(LocalDateTime.parse(pageVO.getStartDate().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER))
                    .and(qOrder.createTime.before(LocalDateTime.parse(pageVO.getEndDate().concat(" 23:59:59"), OrderServiceContants.DEFAULT_TIME_FORMATTER))));
        }
        idsQuery.groupBy(qOrderProduct.productNo);
        //获取productNo集合，因为productNo并非唯一，还需要将集合再次分组
        List<String> productNos = idsQuery.fetch().stream().map(DeliveryPlanProductQueryVO::getProductNo).collect(Collectors.toList());
        JPAQuery<DeliveryPlanProductQueryVO> query = jpaQueryFactory
                .select(Projections.constructor(DeliveryPlanProductQueryVO.class,qOrderProduct.name,qOrderProduct.spec,qOrderProduct.category,qOrderProduct.brand,qOrderProduct.unit,qOrderProduct.productNo))
                .from(qOrderProduct)
                .leftJoin(qOrder).on(qOrderProduct.order.id.eq(qOrder.id))
                .where(qOrderProduct.productNo.in(productNos)
                        .and(qOrder.buyerMemberId.eq(buyerMemberId))
                        .and(qOrder.buyerRoleId.eq(buyerRoleId))
                        .and(qOrder.vendorMemberId.eq(vendorMemberId))
                        .and(qOrder.vendorRoleId.eq(vendorRoleId))
                        .and(qOrder.orderType.in(orderTypes))
                        .and(qOrder.outerStatus.in(orderOuterStatus)));
        if(org.springframework.util.StringUtils.hasLength(pageVO.getStartDate()) && org.springframework.util.StringUtils.hasLength(pageVO.getEndDate())) {
            query.where(qOrder.createTime.after(LocalDateTime.parse(pageVO.getStartDate().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER))
                    .and(qOrder.createTime.before(LocalDateTime.parse(pageVO.getEndDate().concat(" 23:59:59"), OrderServiceContants.DEFAULT_TIME_FORMATTER))));
        }
        query.groupBy(qOrderProduct.name,qOrderProduct.spec,qOrderProduct.category,qOrderProduct.brand,qOrderProduct.unit,qOrderProduct.productNo);
        List<DeliveryPlanProductQueryVO> planProducts = query.limit(pageVO.getPageSize()).offset(pageVO.getCurrentOffset()).fetch();
        //根据已分页的productNo集合再去查订单数据
        List<String> productNoList = planProducts.stream().map(DeliveryPlanProductQueryVO::getProductNo).collect(Collectors.toList());
        JPAQuery<DeliveryPlanOrderQueryVO> orderQuery = jpaQueryFactory.select(Projections.constructor(DeliveryPlanOrderQueryVO.class,
                qOrder.orderNo, qOrder.digest, qOrder.createTime,
                qOrderProduct.quantity, qOrderProduct.received, qOrderProduct.delivered,
                qOrderConsignee.consigneeId, qOrderConsignee.consignee, qOrderConsignee.provinceName,
                qOrderConsignee.cityName, qOrderConsignee.districtName, qOrderConsignee.streetName,
                qOrderConsignee.address, qOrderConsignee.phone, qOrderProduct.leftCount,
                qOrderProduct.id, qOrderProduct.productNo, qOrderProduct.name,qOrderProduct.noticeCount,qOrderProduct.spec))
                .from(qOrderProduct)
                .leftJoin(qOrder).on(qOrderProduct.order.id.eq(qOrder.id))
                .leftJoin(qOrderConsignee).on(qOrderProduct.order.id.eq(qOrderConsignee.order.id))
                .where(qOrder.buyerMemberId.eq(buyerMemberId)
                        .and(qOrder.buyerRoleId.eq(buyerRoleId))
                        .and(qOrder.vendorMemberId.eq(vendorMemberId))
                        .and(qOrder.vendorRoleId.eq(vendorRoleId))
                        .and(qOrder.orderType.in(orderTypes))
                        .and(qOrder.outerStatus.in(orderOuterStatus))
                        .and(qOrderProduct.productNo.in(productNoList)));

        //拿到所有订单数据
        if(org.springframework.util.StringUtils.hasLength(pageVO.getStartDate()) && org.springframework.util.StringUtils.hasLength(pageVO.getEndDate())) {
            orderQuery.where(qOrder.createTime.after(LocalDateTime.parse(pageVO.getStartDate().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER))
                    .and(qOrder.createTime.before(LocalDateTime.parse(pageVO.getEndDate().concat(" 23:59:59"), OrderServiceContants.DEFAULT_TIME_FORMATTER))));
        }
        orderQuery.groupBy(qOrder.orderNo, qOrder.digest, qOrder.createTime,
                qOrderProduct.quantity, qOrderProduct.received, qOrderProduct.delivered,
                qOrderConsignee.consigneeId, qOrderConsignee.consignee, qOrderConsignee.provinceName,
                qOrderConsignee.cityName, qOrderConsignee.districtName, qOrderConsignee.streetName,
                qOrderConsignee.address, qOrderConsignee.phone, qOrderProduct.leftCount,
                qOrderProduct.id, qOrderProduct.productNo, qOrderProduct.name,qOrderProduct.noticeCount,qOrderProduct.spec);
        List<DeliveryPlanOrderQueryVO> orders = orderQuery.fetch();
        Integer no = 1;
        for (DeliveryPlanProductQueryVO deliveryPlanProductQueryVO : planProducts) {
            deliveryPlanProductQueryVO.setNo(no);
            no = ++no;
            //根据productNo和物料名称还有物料规格进行归类
            List<DeliveryPlanOrderQueryVO> deliveryPlanOrders = orders.stream().filter(o -> o.getSkuId().equals(deliveryPlanProductQueryVO.getSkuId()) && o.getProductName().equals(deliveryPlanProductQueryVO.getProductName()) && o.getSpec().equals(deliveryPlanProductQueryVO.getSpec())).collect(Collectors.toList());
            BigDecimal purchaseCount = BigDecimal.ZERO;
            BigDecimal receiveCount = BigDecimal.ZERO;
            BigDecimal transitCount = BigDecimal.ZERO;
            BigDecimal leftCount = BigDecimal.ZERO;
            BigDecimal unplannedCount = BigDecimal.ZERO;
            for (DeliveryPlanOrderQueryVO order : deliveryPlanOrders) {
                purchaseCount = purchaseCount.add(order.getPurchaseCount());
                receiveCount = receiveCount.add(order.getReceiveCount());
                transitCount = transitCount.add(order.getTransitCount());
                leftCount = leftCount.add(order.getLeftCount());
                unplannedCount = unplannedCount.add(order.getUnplannedCount());
            }
            deliveryPlanProductQueryVO.setPurchaseCountSum(purchaseCount);
            deliveryPlanProductQueryVO.setReceiveCountSum(receiveCount);
            deliveryPlanProductQueryVO.setTransitCountSum(transitCount);
            deliveryPlanProductQueryVO.setLeftCountSum(leftCount);
            deliveryPlanProductQueryVO.setPlanCountSum(BigDecimal.ZERO);
            deliveryPlanProductQueryVO.setUnplannedCountSum(unplannedCount);
            deliveryPlanProductQueryVO.setOrders(deliveryPlanOrders);
        }
        long totalCount = query.fetch().size();
        return Wrapper.success(new PageData<>(totalCount, planProducts));
    }


    /**
     * 送货通知单-创建送货通知单
     * @param headers Http头部信息
     * @param param 接口参数
     * @return 操作结果
     */
    @Transactional
    @Override
    public Wrapper<Void> createNoticeOrder(HttpHeaders headers, NoticeOrderParamVO param, Integer type) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        LocalDateTime deliveryTime = LocalDateTime.parse(param.getDeliveryTime().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER);
        if(verifyCreateTime(deliveryTime)){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_NOTICE_CREATE_TIME_ERROR);
        }
        List<NoticeProductParamVO> products = param.getProducts();
        List<Long> planOrderIdList = products.stream().map(NoticeProductParamVO::getPlanOrderId).collect(Collectors.toList());
        //校验当前商品物料和是否生成成过通知单
        if(!StringUtils.isEmpty(param.getPlanNo()) && checkDayStatus(planOrderIdList,deliveryTime)){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_NOTICE_CREATE_COUNT_ERROR);
        }
        DeliveryNoticeOrderDO order = new DeliveryNoticeOrderDO(loginUser.getMemberId(),loginUser.getMemberRoleId(),loginUser.getCompany());
        order.setBuyerMemberId(param.getBuyerMemberId());
        order.setType(type);
        order.setPlanNo(param.getPlanNo());
        order.setBuyerRoleId(param.getBuyerRoleId());
        order.setBuyerMemberName(param.getBuyerMemberName());
        order.setCreateTime(LocalDateTime.now());
        order.setRemark(param.getRemark());
        order.setNoticeNo(createOrderSn(BaseDeliveryEnum.NOTICE_ORDER_SERIAL_NO.getName()));
        order.setDigest(param.getDigest());
        order.setConsigneeId(param.getConsigneeId());
        order.setDeliveryTime(deliveryTime);
        order.setDeliveryStartTime(param.getDeliveryStartTime());
        order.setDeliveryEndTime(param.getDeliveryEndTime());
        order.setConsignee(param.getConsignee());
        order.setProvinceName(param.getProvinceName());
        order.setCityName(param.getCityName());
        order.setDistrictName(param.getDistrictName());
        order.setStreetName(param.getStreetName());
        order.setAddress(param.getAddress());
        order.setPhone(param.getPhone());
        order.setOuterStatus(DeliveryOuterStatusEnum.WAIT_CONFIRM.getCode());
        order.setStatus(DeliveryNoticeOrderStatusEnum.WAIT_CONFIRM.getCode());
        List<Long> productIds = products.stream().map(NoticeProductParamVO::getOrderProductId).collect(Collectors.toList());
        Map<Long, OrderProductDO> orderProductMap = orderProductRepository.findByIdIn(productIds).stream().collect(Collectors.toMap(OrderProductDO::getId, OrderProductDO -> OrderProductDO));
        //送货数量校验
        for (NoticeProductParamVO product : products) {
            OrderProductDO orderProduct = orderProductMap.get(product.getOrderProductId());
            if(Objects.isNull(orderProduct)){
                return Wrapper.fail(ResponseCode.ORDER_DELIVERY_NOTICE_CREATE_PRODUCT_ERROR);
            }
            BigDecimal noticeCount = orderProduct.getNoticeCount() == null ? BigDecimal.ZERO : orderProduct.getNoticeCount();
            if(orderProduct.getQuantity().compareTo(product.getPlanCount().add(noticeCount)) < 0){
                return Wrapper.fail(ResponseCode.ORDER_DELIVERY_NOTICE_CREATE_PLAN_COUNT_ERROR);
            }
        }
        noticeOrderRepository.save(order);
        Wrapper<SimpleTaskCompleteVO> taskResult = startWorkCompleteFirstTask(loginUser,order.getId(), ProcessEnum.ORDER_DELIVERY_NOTICE_ORDER.getProcessKey());
        if (ResponseCode.SUCCESS.getCode() != taskResult.getCode()) {
            throw new RuntimeException(taskResult.getMessage());
        }
        order.setTaskId(taskResult.getData().getTaskId());
        order.setOuterStatus(taskResult.getData().getStatus());
        noticeOrderRepository.save(order);
        List<DeliveryNoticeProductDO> collect = products.stream().map(product -> {
            DeliveryNoticeProductDO deliveryNoticeProductDO = new DeliveryNoticeProductDO();
            deliveryNoticeProductDO.setNoticeOrder(order);
            deliveryNoticeProductDO.setSkuId(product.getSkuId());
            deliveryNoticeProductDO.setOrderProductId(product.getOrderProductId());
            deliveryNoticeProductDO.setPlanOrderId(product.getPlanOrderId());
            deliveryNoticeProductDO.setProductName(product.getProductName());
            deliveryNoticeProductDO.setType(product.getType());
            deliveryNoticeProductDO.setCategory(product.getCategory());
            deliveryNoticeProductDO.setBrand(product.getBrand());
            deliveryNoticeProductDO.setUnit(product.getUnit());
            deliveryNoticeProductDO.setOrderNo(product.getOrderNo());
            deliveryNoticeProductDO.setCreateTime(product.getCreateTime());
            deliveryNoticeProductDO.setPurchaseCount(product.getPurchaseCount());
            deliveryNoticeProductDO.setPlanCount(product.getPlanCount());
            return deliveryNoticeProductDO;
        }).collect(Collectors.toList());
        noticeProductRepository.saveAll(collect);
        //维护订单商品的已通知数量
        updateNoticeCount(collect,true);
        //更新送货计划商品物料生成状态
        if(!StringUtils.isEmpty(param.getPlanNo())){
            updateDayStatus(planOrderIdList,deliveryTime,true);
        }
        //记录单据流转记录
        historyService.saveVendorOuterHistory(loginUser.getMemberId(),loginUser.getMemberRoleId(),loginUser.getUserName(), loginUser.getUserOrgName(),loginUser.getMemberRoleName(),order.getId(),order.getNoticeNo(), DeliveryOperationEnum.CREATE_NOTICE_ORDER, order.getOuterStatus(),param.getRemark(), DeliveryHistoryTypeEnum.NOTICE_ORDER.getCode());
        return Wrapper.success();
    }

    /**
     * 送货通知单-确认送货通知单
     * @param headers Http头部信息
     * @param param 接口参数
     * @return 操作结果
     */
    @Transactional
    @Override
    public Wrapper<Void> confirmNoticeOrder(HttpHeaders headers, DeliveryVerifyVO param) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        DeliveryNoticeOrderDO order = noticeOrderRepository.findById(param.getId()).orElse(null);
        if(Objects.isNull(order) || !loginUser.getMemberId().equals(order.getBuyerMemberId()) || !loginUser.getMemberRoleId().equals(order.getBuyerRoleId())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_NOTICE_ORDER_DOES_NOT_EXIST);
        }
        if(!order.getStatus().equals(DeliveryNoticeOrderStatusEnum.WAIT_CONFIRM.getCode())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_NOTICE_STATUS_CONFIRM_ERROR);
        }
        order.setStatus(param.getIsPass() ? DeliveryNoticeOrderStatusEnum.ALREADY_CONFIRM.getCode() : DeliveryNoticeOrderStatusEnum.WAIT_MODIFY.getCode());
        Wrapper<SimpleTaskCompleteVO> taskResult = executeWork(order.getVendorMemberId(), order.getVendorRoleId(), order.getId(), ProcessEnum.ORDER_DELIVERY_NOTICE_ORDER.getProcessKey(), order.getTaskId(),param.getIsPass() ? ProcessTaskStatusEnum.AGREE.getCode() : ProcessTaskStatusEnum.DISAGREE.getCode());
        if (ResponseCode.SUCCESS.getCode() != taskResult.getCode()) {
            return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
        }
        order.setTaskId(taskResult.getData().getTaskId());
        order.setOuterStatus(taskResult.getData().getStatus());
        order.setRemark(param.getRemark());
        noticeOrderRepository.save(order);
        //记录单据流转记录
        historyService.saveBuyerOuterHistory(loginUser.getMemberId(),loginUser.getMemberRoleId(),loginUser.getUserName(), loginUser.getUserOrgName(),loginUser.getMemberRoleName(),order.getId(),order.getNoticeNo(), DeliveryOperationEnum.CONFIRM_NOTICE_ORDER,order.getOuterStatus(),param.getRemark(), DeliveryHistoryTypeEnum.NOTICE_ORDER.getCode());
        return Wrapper.success();
    }

    /**
     * 送货通知单-修改送货通知单
     * @param headers Http头部信息
     * @param param 接口参数
     * @return 操作结果
     */
    @Transactional
    @Override
    public Wrapper<Void> updateNoticeOrder(HttpHeaders headers, DeliveryNoticeOrderUpdateVO param) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        DeliveryNoticeOrderDO order = noticeOrderRepository.findById(param.getNoticeId()).orElse(null);
        if(Objects.isNull(order) || !loginUser.getMemberId().equals(order.getVendorMemberId()) || !loginUser.getMemberRoleId().equals(order.getVendorRoleId())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_NOTICE_ORDER_DOES_NOT_EXIST);
        }
        //非已确认和待修订送货通知单无法修改
        if(!order.getStatus().equals(DeliveryNoticeOrderStatusEnum.ALREADY_CONFIRM.getCode()) && !order.getStatus().equals(DeliveryNoticeOrderStatusEnum.WAIT_MODIFY.getCode())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_UPDATE_NOTICE_STATUS_ERROR);
        }
        order.setDigest(param.getDigest());
        order.setUpdateTime(LocalDateTime.now());
        order.setStatus(DeliveryNoticeOrderStatusEnum.WAIT_CONFIRM.getCode());
        order.setRemark(param.getRemark());
        order.setDeliveryStartTime(param.getDeliveryStartTime());
        order.setDeliveryEndTime(param.getDeliveryEndTime());
        Wrapper<SimpleTaskCompleteVO> taskResult = startWorkCompleteFirstTask(loginUser,order.getId(), ProcessEnum.ORDER_DELIVERY_NOTICE_ORDER.getProcessKey());
        if (ResponseCode.SUCCESS.getCode() != taskResult.getCode()) {
            return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
        }
        order.setTaskId(taskResult.getData().getTaskId());
        order.setOuterStatus(taskResult.getData().getStatus());
        //如果同过送货计划生成,则只允许修改摘要和配送时间段
        if(order.getPlanNo() != null){
            noticeOrderRepository.save(order);
            historyService.saveVendorOuterHistory(loginUser.getMemberId(),loginUser.getMemberRoleId(),loginUser.getUserName(), loginUser.getUserOrgName(),loginUser.getMemberRoleName(),order.getId(),order.getNoticeNo(), DeliveryOperationEnum.MODIFY_NOTICE_ORDER,order.getOuterStatus(),param.getRemark(), DeliveryHistoryTypeEnum.NOTICE_ORDER.getCode());
            return Wrapper.success();
        }
        order.setDeliveryTime(LocalDateTime.parse(param.getDeliveryTime().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER));
        order.setConsignee(param.getConsignee());
        order.setProvinceName(param.getProvinceName());
        order.setCityName(param.getCityName());
        order.setDistrictName(param.getDistrictName());
        order.setStreetName(param.getStreetName());
        order.setAddress(param.getAddress());
        order.setPhone(param.getPhone());
        noticeOrderRepository.save(order);
        noticeProductRepository.deleteByNoticeOrder(order);
        List<DeliveryNoticeProductDO> deliveryNoticeProducts = param.getProducts().stream().map(product -> {
            DeliveryNoticeProductDO deliveryNoticeProductDO = new DeliveryNoticeProductDO();
            deliveryNoticeProductDO.setNoticeOrder(order);
            deliveryNoticeProductDO.setPlanOrderId(product.getPlanOrderId());
            deliveryNoticeProductDO.setSkuId(product.getSkuId());
            deliveryNoticeProductDO.setProductName(product.getProductName());
            deliveryNoticeProductDO.setOrderProductId(product.getOrderProductId());
            deliveryNoticeProductDO.setType(product.getType());
            deliveryNoticeProductDO.setCategory(product.getCategory());
            deliveryNoticeProductDO.setBrand(product.getBrand());
            deliveryNoticeProductDO.setUnit(product.getUnit());
            deliveryNoticeProductDO.setOrderNo(product.getOrderNo());
            deliveryNoticeProductDO.setCreateTime(product.getCreateTime());
            deliveryNoticeProductDO.setPurchaseCount(product.getPurchaseCount());
            deliveryNoticeProductDO.setPlanCount(product.getPlanCount());
            return deliveryNoticeProductDO;
        }).collect(Collectors.toList());
        noticeProductRepository.saveAll(deliveryNoticeProducts);
        //记录送货通知单外部流转记录
        historyService.saveVendorOuterHistory(loginUser.getMemberId(),loginUser.getMemberRoleId(),loginUser.getUserName(), loginUser.getUserOrgName(),loginUser.getMemberRoleName(),order.getId(),order.getNoticeNo(), DeliveryOperationEnum.MODIFY_NOTICE_ORDER,order.getOuterStatus(),param.getRemark(), DeliveryHistoryTypeEnum.NOTICE_ORDER.getCode());
        return Wrapper.success();
    }

    /**
     * 送货计划-确认送货计划
     * @param headers Http头部信息
     * @param param 接口参数
     * @return 操作结果
     */
    @Transactional
    @Override
    public Wrapper<Void> confirmDeliveryPlan(HttpHeaders headers, DeliveryVerifyVO param) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        DeliveryPlanDO deliveryPlan = planRepository.findById(param.getId()).orElse(null);
        if(Objects.isNull(deliveryPlan) || !loginUser.getMemberId().equals(deliveryPlan.getVendorMemberId()) || !loginUser.getMemberRoleId().equals(deliveryPlan.getVendorRoleId())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_DOES_NOT_EXIST);
        }
        if(!deliveryPlan.getStatus().equals(DeliveryPlanStatusEnum.WAIT_CONFIRM.getCode())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_STATUS_CONFIRM_ERROR);
        }
        Wrapper<SimpleTaskCompleteVO> taskResult = executeWork(deliveryPlan.getBuyerMemberId(), deliveryPlan.getBuyerRoleId(), deliveryPlan.getId(), ProcessEnum.ORDER_DELIVERY_PLAN.getProcessKey(), deliveryPlan.getTaskId(),param.getIsPass() ? ProcessTaskStatusEnum.AGREE.getCode() : ProcessTaskStatusEnum.DISAGREE.getCode());
        if (ResponseCode.SUCCESS.getCode() != taskResult.getCode()) {
            return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
        }
        deliveryPlan.setTaskId(taskResult.getData().getTaskId());
        deliveryPlan.setOuterStatus(taskResult.getData().getStatus());
        deliveryPlan.setStatus(param.getIsPass() ? DeliveryPlanStatusEnum.ALREADY_CONFIRM.getCode() : DeliveryPlanStatusEnum.WAIT_MODIFY.getCode());
        deliveryPlan.setUpdateTime(LocalDateTime.now());
        planRepository.saveAndFlush(deliveryPlan);
        //记录单据流转记录
        historyService.saveVendorOuterHistory(loginUser.getMemberId(),loginUser.getMemberRoleId(),loginUser.getUserName(), loginUser.getUserOrgName(),loginUser.getMemberRoleName(),deliveryPlan.getId(),deliveryPlan.getPlanNo(), DeliveryOperationEnum.CONFIRM_DELIVERY_PLAN,deliveryPlan.getOuterStatus(),param.getRemark(), DeliveryHistoryTypeEnum.DELIVERY_PLAN.getCode());
        return Wrapper.success();
    }

    /**
     * 送货计划-供应商送货计划详情
     * @param headers Http头部信息
     * @param idVO    接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<DeliveryPlanDetailVO> getVendorDeliveryPlanDetail(HttpHeaders headers, IdVO idVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        DeliveryPlanDO deliveryPlanDO = planRepository.findById(idVO.getId()).orElse(null);
        if(Objects.isNull(deliveryPlanDO) || !loginUser.getMemberId().equals(deliveryPlanDO.getVendorMemberId()) || !loginUser.getMemberRoleId().equals(deliveryPlanDO.getVendorRoleId())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_DOES_NOT_EXIST);
        }
        return getDeliveryPlanDetail(headers,deliveryPlanDO);
    }

    /**
     * 送货通知单-采购商获取送货通知单详情
     * @param headers Http头部信息
     * @param idVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<DeliveryPlanDetailVO> getBuyerDeliveryPlanDetail(HttpHeaders headers, IdVO idVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        DeliveryPlanDO deliveryPlanDO = planRepository.findById(idVO.getId()).orElse(null);
        if(Objects.isNull(deliveryPlanDO) || !loginUser.getMemberId().equals(deliveryPlanDO.getBuyerMemberId()) || !loginUser.getMemberRoleId().equals(deliveryPlanDO.getBuyerRoleId())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_DOES_NOT_EXIST);
        }
        return getDeliveryPlanDetail(headers,deliveryPlanDO);
    }

    /**
     * 送货计划-获取送货计划详情
     * @param headers Http头部信息
     * @param param    接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<DeliveryPlanDetailVO> getDeliveryPlanDetail(HttpHeaders headers, DeliveryPlanDO param) {
        DeliveryPlanDetailVO plan = new DeliveryPlanDetailVO();
        BeanUtils.copyProperties(param,plan);
        plan.setOuterHistoryList(new ArrayList<>());
        return Wrapper.success(plan);
    }

    /**
     * 送货计划-获取送货通知单详情
     * @param headers Http头部信息
     * @param idVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<DeliveryPlanDetailVO> getDeliveryPlanDetail(HttpHeaders headers, IdVO idVO) {
        DeliveryPlanDO deliveryPlanDO = planRepository.findById(idVO.getId()).orElse(null);
        return getDeliveryPlanDetail(headers,deliveryPlanDO);
    }

    /**
     * 送货计划-送货计划详情中物料信息
     * @param headers Http头部信息
     * @param param 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<PageData<DeliveryPlanProductQueryVO>> getDeliveryPlanProductDetail(HttpHeaders headers, IdPageVO param) {
        DeliveryPlanDO deliveryPlanDO = planRepository.findById(param.getId()).orElse(null);
        List<String> days = planDay(deliveryPlanDO.getPlanStartTime(), deliveryPlanDO.getPlanEndTime());
        Pageable pageable = PageRequest.of(param.getCurrent() - 1, param.getPageSize(), Sort.by("id").descending());
        Page<DeliveryPlanProductDO> byDeliveryPlan = planProductRepository.findByDeliveryPlan(deliveryPlanDO, pageable);
        List<DeliveryPlanProductQueryVO> collect = byDeliveryPlan.stream().map(a -> {
            DeliveryPlanProductQueryVO deliveryPlanProductDO = new DeliveryPlanProductQueryVO();
            deliveryPlanProductDO.setSkuId(a.getSkuId());
            deliveryPlanProductDO.setProductNo(a.getSkuId());
            deliveryPlanProductDO.setProductName(a.getProductName());
            deliveryPlanProductDO.setSpec(a.getType());
            deliveryPlanProductDO.setCategory(a.getCategory());
            deliveryPlanProductDO.setBrand(a.getBrand());
            deliveryPlanProductDO.setUnit(a.getUnit());
            deliveryPlanProductDO.setPurchaseCountSum(a.getPurchaseCount());
            BigDecimal planCountSum = BigDecimal.ZERO;
            BigDecimal transitCount = BigDecimal.ZERO;
            BigDecimal receiveCount = BigDecimal.ZERO;
            BigDecimal leftCount = BigDecimal.ZERO;
            Set<DeliveryPlanOrderDO> deliveryPlanOrders = a.getDeliveryPlanOrders();
            HashMap<String, BigDecimal> dayNumbers = new HashMap<>();
            for (String day : days) {
                dayNumbers.put(day,BigDecimal.ZERO);
            }
            List<DeliveryPlanOrderQueryVO> orders = new ArrayList<>();
            for (DeliveryPlanOrderDO deliveryPlanOrder : deliveryPlanOrders) {
                DeliveryPlanOrderQueryVO deliveryPlanOrderQueryVO = new DeliveryPlanOrderQueryVO();
                deliveryPlanOrderQueryVO.setOrderNo(deliveryPlanOrder.getOrderNo());
                deliveryPlanOrderQueryVO.setOrderDigest(deliveryPlanOrder.getOrderDigest());
                deliveryPlanOrderQueryVO.setCreateTime(deliveryPlanOrder.getCreateTime());
                deliveryPlanOrderQueryVO.setPurchaseCount(deliveryPlanOrder.getPurchaseCount());
                deliveryPlanOrderQueryVO.setReceiveCount(deliveryPlanOrder.getReceiveCount());
                deliveryPlanOrderQueryVO.setTransitCount(deliveryPlanOrder.getTransitCount());
                deliveryPlanOrderQueryVO.setLeftCount(deliveryPlanOrder.getLeftCount());
                deliveryPlanOrderQueryVO.setConsigneeId(deliveryPlanOrder.getConsigneeId());
                deliveryPlanOrderQueryVO.setConsignee(deliveryPlanOrder.getConsignee());
                deliveryPlanOrderQueryVO.setProvinceName(deliveryPlanOrder.getProvinceName());
                deliveryPlanOrderQueryVO.setCityName(deliveryPlanOrder.getCityName());
                deliveryPlanOrderQueryVO.setDistrictName(deliveryPlanOrder.getDistrictName());
                deliveryPlanOrderQueryVO.setSkuId(deliveryPlanOrder.getSkuId());
                deliveryPlanOrderQueryVO.setStreetName(deliveryPlanOrder.getStreetName());
                deliveryPlanOrderQueryVO.setAddress(deliveryPlanOrder.getAddress());
                deliveryPlanOrderQueryVO.setPhone(deliveryPlanOrder.getPhone());
                deliveryPlanOrderQueryVO.setPlanOrderId(deliveryPlanOrder.getId());
                deliveryPlanOrderQueryVO.setOrderProductId(deliveryPlanOrder.getOrderProductId());
                BigDecimal planCount = BigDecimal.ZERO;
                List<DeliveryPlanDayBO> planDays = deliveryPlanOrder.getPlanDays();
                deliveryPlanOrderQueryVO.setPlanDays(planDays);
                for (DeliveryPlanDayBO planDay : planDays) {
                    String day = planDay.getDay();
                    BigDecimal number = dayNumbers.get(day);
                    planCount = planCount.add(planDay.getPlanCount());
                    dayNumbers.put(day,number.add(planDay.getPlanCount()));
                }
                transitCount = transitCount.add(deliveryPlanOrderQueryVO.getTransitCount());
                receiveCount = receiveCount.add(deliveryPlanOrderQueryVO.getReceiveCount());
                leftCount = leftCount.add(deliveryPlanOrderQueryVO.getLeftCount());
                planCountSum = planCountSum.add(planCount);
                deliveryPlanOrderQueryVO.setPlanCount(planCount);
                orders.add(deliveryPlanOrderQueryVO);
            }
            deliveryPlanProductDO.setOrders(orders);
            deliveryPlanProductDO.setDayNumbers(dayNumbers);
            deliveryPlanProductDO.setPlanCountSum(planCountSum);
            deliveryPlanProductDO.setTransitCountSum(transitCount);
            deliveryPlanProductDO.setReceiveCountSum(receiveCount);
            deliveryPlanProductDO.setLeftCountSum(leftCount);
            return deliveryPlanProductDO;
        }).collect(Collectors.toList());
        return Wrapper.success(new PageData<>(byDeliveryPlan.getTotalElements(), collect));
    }

    /**
     * 送货计划-供应商查询送货计划
     * @param headers  Http头部信息
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<DeliveryPlanQueryVO>> pageVendorDeliveryPlan(HttpHeaders headers, DeliveryPlanPageVO pageVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        List<Integer> status = Stream.of(DeliveryPlanStatusEnum.WAIT_CONFIRM.getCode(),DeliveryPlanStatusEnum.ALREADY_CONFIRM.getCode()).collect(Collectors.toList());
        return pagePlan(loginUser,pageVO,status,RoleTypeEnum.SERVICE_PROVIDER.getCode(),null);
    }

    /**
     * 送货计划-采购商查询送货计划
     * @param headers  Http头部信息
     * @param pageVO 接口参数
     * @param type DeliveryOrderTypeStatusEnum
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<DeliveryPlanQueryVO>> pageBuyerDeliveryPlan(HttpHeaders headers, DeliveryPlanPageVO pageVO,Integer type) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        List<Integer> status = Stream.of(DeliveryPlanStatusEnum.WAIT_SUBMIT.getCode(),DeliveryPlanStatusEnum.WAIT_MODIFY.getCode(),DeliveryPlanStatusEnum.WAIT_CONFIRM.getCode(),DeliveryPlanStatusEnum.ALREADY_CONFIRM.getCode()).collect(Collectors.toList());
        return pagePlan(loginUser,pageVO,status,RoleTypeEnum.SERVICE_CONSUMER.getCode(),type);
    }

    /**
     * 送货通知单-供应商查询送货通知单
     * @param headers  Http头部信息
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<NoticeOrderQueryVO>> pageVendorNoticeOrder(HttpHeaders headers, NoticeOrderPageVO pageVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        QDeliveryNoticeOrderDO qDeliveryNoticeOrder = QDeliveryNoticeOrderDO.deliveryNoticeOrderDO;
        JPAQuery<NoticeOrderQueryVO> query = jpaQueryFactory
                .select(Projections.constructor(NoticeOrderQueryVO.class, qDeliveryNoticeOrder.id, qDeliveryNoticeOrder.noticeNo, qDeliveryNoticeOrder.digest, qDeliveryNoticeOrder.createTime, qDeliveryNoticeOrder.deliveryTime, qDeliveryNoticeOrder.buyerMemberName, qDeliveryNoticeOrder.status ,qDeliveryNoticeOrder.type))
                .from(qDeliveryNoticeOrder);
        //固定条件
        query.where(qDeliveryNoticeOrder.vendorMemberId.eq(loginUser.getMemberId()).and(qDeliveryNoticeOrder.vendorRoleId.eq(loginUser.getMemberRoleId())));

        //外部状态
        if(pageVO.getStatus() != null) {
            query.where(qDeliveryNoticeOrder.status.eq(pageVO.getStatus()));
        }

        //通知单号
        if(!StringUtils.isEmpty(pageVO.getNoticeNo())) {
            query.where(qDeliveryNoticeOrder.noticeNo.like("%" + pageVO.getNoticeNo().trim() + "%"));
        }

        //订单类型
        if(pageVO.getOrderType() != null) {
            query.where(qDeliveryNoticeOrder.type.eq(pageVO.getOrderType()));
        }

        //摘要
        if(!StringUtils.isEmpty(pageVO.getDigest())) {
            query.where(qDeliveryNoticeOrder.digest.like("%" + pageVO.getDigest().trim() + "%"));
        }

        //会员名称
        if(!StringUtils.isEmpty(pageVO.getMemberName())) {
            query.where(qDeliveryNoticeOrder.buyerMemberName.like("%" + pageVO.getMemberName().trim() + "%"));
        }

        //起始时间
        if(!StringUtils.isEmpty(pageVO.getStartDate())) {
            query.where(qDeliveryNoticeOrder.deliveryTime.after(LocalDateTime.parse(pageVO.getStartDate().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER)));
        }

        //结束时间
        if(!StringUtils.isEmpty(pageVO.getEndDate())) {
            query.where(qDeliveryNoticeOrder.deliveryTime.before(LocalDateTime.parse(pageVO.getStartDate().concat(" 23:59:59"), OrderServiceContants.DEFAULT_TIME_FORMATTER)));
        }
        //倒序排序、分页、总数
        query.orderBy(qDeliveryNoticeOrder.createTime.desc());
        query.limit(pageVO.getPageSize()).offset(pageVO.getCurrentOffset());
        long totalCount = query.fetchCount();
        return Wrapper.success(new PageData<>(totalCount, query.fetch()));
    }

    /**
     * 送货通知单-采购商查询送货通知单
     * @param headers  Http头部信息
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<NoticeOrderQueryVO>> pageBuyerNoticeOrder(HttpHeaders headers, NoticeOrderPageVO pageVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        QDeliveryNoticeOrderDO qDeliveryNoticeOrder = QDeliveryNoticeOrderDO.deliveryNoticeOrderDO;
        JPAQuery<NoticeOrderQueryVO> query = jpaQueryFactory
                .select(Projections.constructor(NoticeOrderQueryVO.class, qDeliveryNoticeOrder.id, qDeliveryNoticeOrder.noticeNo, qDeliveryNoticeOrder.digest, qDeliveryNoticeOrder.createTime, qDeliveryNoticeOrder.deliveryTime, qDeliveryNoticeOrder.vendorMemberName, qDeliveryNoticeOrder.status, qDeliveryNoticeOrder.type))
                .from(qDeliveryNoticeOrder);
        //固定条件
        query.where(qDeliveryNoticeOrder.buyerMemberId.eq(loginUser.getMemberId()).and(qDeliveryNoticeOrder.buyerRoleId.eq(loginUser.getMemberRoleId())));

        //外部状态
        if(pageVO.getStatus() != null) {
            query.where(qDeliveryNoticeOrder.status.eq(pageVO.getStatus()));
        }

        //通知单号
        if(!StringUtils.isEmpty(pageVO.getNoticeNo())) {
            query.where(qDeliveryNoticeOrder.noticeNo.like("%" + pageVO.getNoticeNo().trim() + "%"));
        }

        //订单类型
        if(pageVO.getOrderType() != null) {
            query.where(qDeliveryNoticeOrder.type.eq(pageVO.getOrderType()));
        }

        //摘要
        if(!StringUtils.isEmpty(pageVO.getDigest())) {
            query.where(qDeliveryNoticeOrder.digest.like("%" + pageVO.getDigest().trim() + "%"));
        }

        //会员名称
        if(!StringUtils.isEmpty(pageVO.getMemberName())) {
            query.where(qDeliveryNoticeOrder.vendorMemberName.like("%" + pageVO.getMemberName().trim() + "%"));
        }

        //起始时间
        if(!StringUtils.isEmpty(pageVO.getStartDate())) {
            query.where(qDeliveryNoticeOrder.deliveryTime.after(LocalDateTime.parse(pageVO.getStartDate().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER)));
        }

        //结束时间
        if(!StringUtils.isEmpty(pageVO.getEndDate())) {
            query.where(qDeliveryNoticeOrder.deliveryTime.before(LocalDateTime.parse(pageVO.getStartDate().concat(" 23:59:59"), OrderServiceContants.DEFAULT_TIME_FORMATTER)));
        }
        //倒序排序、分页、总数
        query.orderBy(qDeliveryNoticeOrder.createTime.desc());
        query.limit(pageVO.getPageSize()).offset(pageVO.getCurrentOffset());
        long totalCount = query.fetchCount();
        return Wrapper.success(new PageData<>(totalCount, query.fetch()));
    }

    /**
     * 送货通知单-获取送货通知单详情
     * @param headers Http头部信息
     * @param orderDO    接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<NoticeOrderDetailVO> getNoticeOrderDetail(HttpHeaders headers, DeliveryNoticeOrderDO orderDO) {
        NoticeOrderDetailVO noticeOrderDetailVO = new NoticeOrderDetailVO();
        BeanUtils.copyProperties(orderDO,noticeOrderDetailVO);
        //外部流转记录
        noticeOrderDetailVO.setDeliveryTime(orderDO.getDeliveryTime().format(OrderServiceContants.DEFAULT_DATE_FORMATTER));
        noticeOrderDetailVO.setOuterHistoryList(new ArrayList<>());
        return Wrapper.success(noticeOrderDetailVO);
    }

    /**
     * 送货通知单-获取送货通知单详情
     * @param headers Http头部信息
     * @param idVO    接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<NoticeOrderDetailVO> getNoticeOrderDetail(HttpHeaders headers, IdVO idVO) {
        DeliveryNoticeOrderDO orderDO = noticeOrderRepository.findById(idVO.getId()).orElse(null);
        if(Objects.isNull(orderDO)){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_NOTICE_ORDER_DOES_NOT_EXIST);
        }
        return getNoticeOrderDetail(headers,orderDO);
    }

    /**
     * 送货通知单-采购商获取送货通知单详情
     * @param headers Http头部信息
     * @param idVO    接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<NoticeOrderDetailVO> getBuyerNoticeOrderDetail(HttpHeaders headers, IdVO idVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        DeliveryNoticeOrderDO orderDO = noticeOrderRepository.findById(idVO.getId()).orElse(null);
        if(Objects.isNull(orderDO) || !loginUser.getMemberId().equals(orderDO.getBuyerMemberId()) || !loginUser.getMemberRoleId().equals(orderDO.getBuyerRoleId())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_NOTICE_ORDER_DOES_NOT_EXIST);
        }
        return getNoticeOrderDetail(headers,orderDO);
    }

    /**
     * 送货通知单-供应商获取送货通知单详情
     * @param headers Http头部信息
     * @param idVO    接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<NoticeOrderDetailVO> getVendorNoticeOrderDetail(HttpHeaders headers, IdVO idVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        DeliveryNoticeOrderDO orderDO = noticeOrderRepository.findById(idVO.getId()).orElse(null);
        if(Objects.isNull(orderDO) || !loginUser.getMemberId().equals(orderDO.getVendorMemberId()) || !loginUser.getMemberRoleId().equals(orderDO.getVendorRoleId())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_NOTICE_ORDER_DOES_NOT_EXIST);
        }
        return getNoticeOrderDetail(headers,orderDO);
    }

    /**
     * 送货通知单-查询送货通知单送货物料列表
     * @param headers Http头部信息
     * @param pageVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<NoticeOrderProductQueryVO>> pageNoticeOrderProducts(HttpHeaders headers, NoticeOrderIdPageVO pageVO) {
        DeliveryNoticeOrderDO orderDO = noticeOrderRepository.findById(pageVO.getOrderId()).orElse(null);
        if(Objects.isNull(orderDO)){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_NOTICE_ORDER_DOES_NOT_EXIST);
        }
        QDeliveryNoticeProductDO deliveryNoticeProduct = QDeliveryNoticeProductDO.deliveryNoticeProductDO;
        JPAQuery<NoticeOrderProductQueryVO> query = jpaQueryFactory.
                select(Projections.constructor(NoticeOrderProductQueryVO.class,deliveryNoticeProduct.id,deliveryNoticeProduct.skuId,deliveryNoticeProduct.productName,deliveryNoticeProduct.type,deliveryNoticeProduct.category,deliveryNoticeProduct.brand,deliveryNoticeProduct.unit,deliveryNoticeProduct.orderNo,deliveryNoticeProduct.createTime,deliveryNoticeProduct.purchaseCount,deliveryNoticeProduct.planCount,deliveryNoticeProduct.orderProductId,deliveryNoticeProduct.planOrderId))
                .from(deliveryNoticeProduct);
        query.where(deliveryNoticeProduct.noticeOrder.eq(orderDO));
        //倒序排序、分页、总数
        query.orderBy(deliveryNoticeProduct.id.desc());
        query.limit(pageVO.getPageSize()).offset(pageVO.getCurrentOffset());
        long totalCount = query.fetchCount();
        return Wrapper.success(new PageData<>(totalCount, query.fetch()));
    }

    /**
     * 送货通知单-作废送货通知单
     * @param headers Http头部信息
     * @param param 接口参数
     * @return 操作结果
     */
    @Transactional
    @Override
    public Wrapper<Void> invalidNoticeOrder(HttpHeaders headers, DeliveryInvalidVO param) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        DeliveryNoticeOrderDO order = noticeOrderRepository.findById(param.getId()).orElse(null);
        if(Objects.isNull(order) || order.getStatus().equals(DeliveryNoticeOrderStatusEnum.CREATE_DELIVERY_ORDER.getCode()) || order.getStatus().equals(DeliveryNoticeOrderStatusEnum.INVALID.getCode())) {
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_NOTICE_ORDER_STATUS_CAN_NOT_INVALID);
        }
        order.setUpdateTime(LocalDateTime.now());
        order.setStatus(DeliveryNoticeOrderStatusEnum.INVALID.getCode());
        order.setRemark(param.getRemark());
        Set<DeliveryNoticeProductDO> deliveryNoticeProducts = order.getDeliveryNoticeProducts();
        //将送货计划里的送货天数状态改为未生成
        if(!StringUtils.isEmpty(order.getPlanNo())){
            List<Long> planOrderIdList = deliveryNoticeProducts.stream().map(DeliveryNoticeProductDO::getPlanOrderId).collect(Collectors.toList());
            updateDayStatus(planOrderIdList,order.getDeliveryTime(),false);
        }
        //将订单商品中的待计划发货数量归还
        updateNoticeCount(new ArrayList<>(deliveryNoticeProducts),false);
        noticeOrderRepository.saveAndFlush(order);
        //记录单据流转记录
        historyService.saveVendorOuterHistory(loginUser.getMemberId(),loginUser.getMemberRoleId(),loginUser.getUserName(), loginUser.getUserOrgName(),loginUser.getMemberRoleName(),order.getId(),order.getNoticeNo(), DeliveryOperationEnum.INVALID_NOTICE_ORDER,order.getOuterStatus(),param.getRemark(), DeliveryHistoryTypeEnum.NOTICE_ORDER.getCode());
        return Wrapper.success();
    }

    /**
     * 新增订单时新增送货计划物料数据
     * @param order 订单
     */
    @Transactional
    @Override
    public void saveDeliveryPlanProduct(OrderDO order) {
        logger.error("送货计划 - 进入订单时新增送货计划物料数据接口，订单id："+order.getId());
        //获取订单类型，符合b2b，srm订单则进行下一步
        Integer planTypeByOrderType = getPlanTypeByOrderType(order);
        if(!planTypeByOrderType.equals(DeliveryOrderTypeStatusEnum.UNKNOWN.getCode())){
            LocalDateTime createTime = order.getCreateTime();
            OrderConsigneeDO consignee = order.getConsignee();
            QDeliveryPlanDO plan = QDeliveryPlanDO.deliveryPlanDO;
            List<DeliveryPlanDO> deliveryPlanDOList = jpaQueryFactory.select(plan).from(plan)
                    .where(plan.buyerMemberId.eq(order.getBuyerMemberId())
                            .and(plan.buyerRoleId.eq(order.getBuyerRoleId()))
                            .and(plan.vendorMemberId.eq(order.getVendorMemberId()))
                            .and(plan.type.eq(planTypeByOrderType))
                            .and(plan.vendorRoleId.eq(order.getVendorRoleId()))
                            .and(plan.planEndTime.after(createTime))).fetch();
            Set<OrderProductDO> products = order.getProducts();
            //拿到所有未结束任务的送货计划
            deliveryPlanDOList.stream().forEach( deliveryPlan -> {
                List<String> days = planDay(deliveryPlan.getPlanStartTime(), deliveryPlan.getPlanEndTime());
                List<DeliveryPlanDayBO> planDayList = days.stream().map(day -> {
                    DeliveryPlanDayBO deliveryPlanDayBO = new DeliveryPlanDayBO();
                    deliveryPlanDayBO.setDay(day);
                    deliveryPlanDayBO.setPlanCount(BigDecimal.ZERO);
                    return deliveryPlanDayBO;
                }).collect(Collectors.toList());
                products.stream().forEach( product -> {
                    DeliveryPlanProductDO planProduct = null;
                    if(planTypeByOrderType.equals(DeliveryOrderTypeStatusEnum.B2B.getCode())){
                        planProduct = planProductRepository.findFirstByDeliveryPlanAndSkuIdAndProductName(deliveryPlan,String.valueOf(product.getSkuId()), product.getName());
                    }else {
                        planProduct = planProductRepository.findFirstByDeliveryPlanAndSkuIdAndProductNameAndType(deliveryPlan,product.getProductNo(), product.getName(),product.getSpec());
                    }
                    if(Objects.isNull(planProduct)){
                        planProduct = new DeliveryPlanProductDO();
                        planProduct.setDeliveryPlan(deliveryPlan);
                        if(planTypeByOrderType.equals(DeliveryOrderTypeStatusEnum.B2B.getCode())){
                            planProduct.setSkuId(String.valueOf(product.getSkuId()));
                        }else {
                            planProduct.setSkuId(product.getProductNo());
                        }
                        planProduct.setProductName(product.getName());
                        planProduct.setType(product.getSpec());
                        planProduct.setCategory(product.getCategory());
                        planProduct.setBrand(product.getBrand());
                        planProduct.setUnit(product.getUnit());
                        planProduct.setPurchaseCount(product.getQuantity());
                        planProduct.setReceiveCount(BigDecimal.ZERO);
                        planProduct.setTransitCount(BigDecimal.ZERO);
                        planProduct.setLeftCount(BigDecimal.ZERO);
                        planProduct.setPlanCount(BigDecimal.ZERO);
                    }else{
                        BigDecimal purchaseCount = planProduct.getPurchaseCount();
                        BigDecimal leftCount = planProduct.getLeftCount();
                        planProduct.setPurchaseCount(purchaseCount.add(product.getQuantity()));
                        planProduct.setLeftCount(leftCount.add(product.getQuantity()));
                    }
                    planProductRepository.save(planProduct);
                    DeliveryPlanOrderDO deliveryPlanOrderDO = new DeliveryPlanOrderDO();
                    deliveryPlanOrderDO.setDeliveryPlanProduct(planProduct);
                    deliveryPlanOrderDO.setOrderNo(order.getOrderNo());
                    deliveryPlanOrderDO.setPlanId(deliveryPlan.getId());
                    deliveryPlanOrderDO.setSkuId(planProduct.getSkuId());
                    deliveryPlanOrderDO.setOrderDigest(order.getDigest());
                    deliveryPlanOrderDO.setCreateTime(order.getCreateTime());
                    deliveryPlanOrderDO.setPurchaseCount(product.getQuantity());
                    deliveryPlanOrderDO.setReceiveCount(BigDecimal.ZERO);
                    deliveryPlanOrderDO.setTransitCount(BigDecimal.ZERO);
                    deliveryPlanOrderDO.setLeftCount(product.getQuantity());
                    deliveryPlanOrderDO.setPlanCount(BigDecimal.ZERO);
                    deliveryPlanOrderDO.setOrderProductId(product.getId());
                    deliveryPlanOrderDO.setConsigneeId(consignee.getConsigneeId());
                    deliveryPlanOrderDO.setConsignee(consignee.getConsignee());
                    deliveryPlanOrderDO.setProvinceName(consignee.getProvinceName());
                    deliveryPlanOrderDO.setCityName(consignee.getCityName());
                    deliveryPlanOrderDO.setDistrictName(consignee.getDistrictName());
                    deliveryPlanOrderDO.setStreetName(consignee.getStreetName());
                    deliveryPlanOrderDO.setAddress(consignee.getAddress());
                    deliveryPlanOrderDO.setPhone(consignee.getPhone());
                    deliveryPlanOrderDO.setPlanDays(planDayList);
                    planOrderRepository.save(deliveryPlanOrderDO);
                });
            });
        }
    }


    /**
     * 中止，取消订单时删除送货计划物料数据
     * @param order 订单
     */
    @Transactional
    @Override
    public void removeDeliveryPlanProduct(OrderDO order) {
        Set<OrderProductDO> products = order.getProducts();
        List<Long> productIds = products.stream().map(OrderProductDO::getId).collect(Collectors.toList());
        Map<Long, OrderProductDO> orderProductDOMap = products.stream().collect(Collectors.toMap(OrderProductDO::getId, OrderProductDO -> OrderProductDO));
        List<DeliveryPlanOrderDO> deliveryPlanOrders = planOrderRepository.findByOrderProductIdIn(productIds);
        deliveryPlanOrders.stream().forEach( planOrder -> {
            OrderProductDO orderProductDO = orderProductDOMap.get(planOrder.getOrderProductId());
            if(Objects.isNull(orderProductDO)){
                DeliveryPlanProductDO planProduct = planOrder.getDeliveryPlanProduct();
                //如果对应订单详情只有一条则删除
                if(planProduct.getDeliveryPlanOrders().size() == 1){
                    planProductRepository.delete(planProduct);
                }
            }
        });
        //删除对应订单商品的送货物料订单数据
        planOrderRepository.deleteByOrderProductIdIn(productIds);
    }

    /**
     * 修改送货单关联送货计划配送物料订单状态
     * @param order 订单
     * @param status DeliveryOrderOuterStatusEnum
     */
    @Transactional
    @Override
    public void updateDeliveryPlanStatus(UserLoginCacheDTO loginUser, DeliveryOrderDO order, Integer status) {
        //仅对来源类型送货计划进行操作
        if(StringUtils.isNotEmpty(order.getSourceNo()) && order.getSourceType() == 1){
            DeliveryPlanDO deliveryPlan = planRepository.findFirstByPlanNo(order.getSourceNo());
            //找到对应送货计划，进行下一步操作
            if( !Objects.isNull(deliveryPlan) && loginUser.getMemberId().equals(deliveryPlan.getVendorMemberId()) && loginUser.getMemberRoleId().equals(deliveryPlan.getVendorRoleId())){
                List<DeliveryOrderProductDO> deliveryOrderProductDOS = deliveryOrderProductRepository.findByDeliveryOrder(order);
                List<Long> orderProductIds = deliveryOrderProductDOS.stream().map(DeliveryOrderProductDO::getOrderProductId).collect(Collectors.toList());
                String day = order.getDeliveryTime().format(DateTimeFormatter.ofPattern("MM-dd"));
                //通过订单商品id获取对应送货计划物料订单数据
                List<DeliveryPlanOrderDO> deliveryPlanOrders = planOrderRepository.findByOrderProductIdInAndPlanId(orderProductIds,deliveryPlan.getId());
                deliveryPlanOrders.stream().forEach( deliveryPlanOrder -> {
                    for (DeliveryPlanDayBO planDay : deliveryPlanOrder.getPlanDays()) {
                        //匹配当前送货单配送日期和送货计划物料订单中的日期数据，修改日期状态
                        if(planDay.getDay().equals(day)){
                            //判断当前订单日期是否已生成过送货单，如果有则报错
                            if(status.equals(DeliveryOrderOuterStatusEnum.ALREADY_SUBMIT.getCode())){
                                if(!planDay.getCreateNotice()){
                                    planDay.setCreateDelivery(true);
                                }else{
                                    throw new BusinessException(ResponseCode.ORDER_DELIVERY_CREATE_DELIVERY_REPETITION_ERROR);
                                }
                            }
                            if(status.equals(DeliveryOrderOuterStatusEnum.INVALID.getCode())){
                                planDay.setCreateDelivery(false);
                            }
                        }
                    }
                });
                planOrderRepository.saveAll(deliveryPlanOrders);
            }else{
                throw new BusinessException(ResponseCode.ORDER_DELIVERY_PLAN_DOES_NOT_EXIST);
            }
        }
    }

    /**
     * 修改送货单关联送货通知单状态（内部接口）
     * @param loginUser 会员信息
     * @param order 订单
     * @param status DeliveryOrderOuterStatusEnum 只针对 1-已提交 和 3-已作废 两个状态生效
     */
    @Transactional
    @Override
    public void updateNoticeOrderStatus(UserLoginCacheDTO loginUser, DeliveryOrderDO order, Integer status) {
        if(StringUtils.isNotEmpty(order.getSourceNo()) && order.getSourceType() == 2){
            DeliveryNoticeOrderDO noticeNo = noticeOrderRepository.findFirstByNoticeNo(order.getSourceNo());
            //找到对应送货计划，进行下一步操作
            if(noticeNo != null && loginUser.getMemberId().equals(noticeNo.getVendorMemberId()) && loginUser.getMemberRoleId().equals(noticeNo.getVendorRoleId())){
                if(status.equals(DeliveryOrderOuterStatusEnum.ALREADY_SUBMIT.getCode())){
                    if(DeliveryNoticeOrderStatusEnum.ALREADY_CONFIRM.getCode().equals(noticeNo.getStatus())){
                        noticeNo.setStatus(DeliveryNoticeOrderStatusEnum.CREATE_DELIVERY_ORDER.getCode());
                        noticeNo.setUpdateTime(LocalDateTime.now());
                        noticeOrderRepository.save(noticeNo);
                    }else{
                        throw new BusinessException(ResponseCode.ORDER_DELIVERY_CREATE_DELIVERY_STATUS_ERROR);
                    }
                }
                if(status.equals(DeliveryOrderOuterStatusEnum.INVALID.getCode())){
                    if(DeliveryNoticeOrderStatusEnum.CREATE_DELIVERY_ORDER.getCode().equals(noticeNo.getStatus())){
                        noticeNo.setStatus(DeliveryNoticeOrderStatusEnum.ALREADY_CONFIRM.getCode());
                        noticeNo.setUpdateTime(LocalDateTime.now());
                        noticeOrderRepository.save(noticeNo);
                    }else{
                        throw new BusinessException(ResponseCode.ORDER_DELIVERY_CREATE_DELIVERY_INVALID_STATUS_ERROR);
                    }
                }
            }else{
                throw new BusinessException(ResponseCode.ORDER_DELIVERY_NOTICE_ORDER_DOES_NOT_EXIST);
            }
        }
    }

    @Transactional
    @Override
    public void updateDeliveryPlanOrder(List<Long> orderProductIds) {
        List<OrderProductDO> orderProductList = orderProductRepository.findByIdIn(orderProductIds);
        Map<Long, OrderProductDO> orderProductMap = orderProductList.stream().collect(Collectors.toMap(OrderProductDO::getId, OrderProductDO -> OrderProductDO));
        List<DeliveryPlanOrderDO> deliveryPlanOrderList = planOrderRepository.findByOrderProductIdIn(orderProductIds);
        for (DeliveryPlanOrderDO deliveryPlanOrderDO : deliveryPlanOrderList) {
            OrderProductDO orderProductDO = orderProductMap.get(deliveryPlanOrderDO.getOrderProductId());
            if(!Objects.isNull(orderProductDO)){
                deliveryPlanOrderDO.setPlanCount(orderProductDO.getNoticeCount());
                deliveryPlanOrderDO.setLeftCount(orderProductDO.getLeftCount());
                deliveryPlanOrderDO.setReceiveCount(orderProductDO.getReceived());
                deliveryPlanOrderDO.setTransitCount(orderProductDO.getDelivered().subtract(orderProductDO.getReceived()));
            }
        }
        planOrderRepository.saveAll(deliveryPlanOrderList);
    }

    /**
     * 根据单据编号和单据类型获取收货地址(如果是送货计划则需要传orderProductId)
     * @param sourceNo 单据编号
     * @param sourceType 单据类型
     * @return 收货地址
     */
    @Override
    public LogisticsAddressVO getReceiveAddressBySourceNoOrOrderProductId(String sourceNo, Integer sourceType,Long orderProductId) {
        LogisticsAddressVO logisticsAddressVO = new LogisticsAddressVO();
        if(sourceType == 1){
            DeliveryPlanOrderDO planOrder = planOrderRepository.findFirstByOrderProductId(orderProductId);
            logisticsAddressVO.setConsignee(planOrder.getConsignee());
            logisticsAddressVO.setProvinceName(planOrder.getProvinceName());
            logisticsAddressVO.setCityName(planOrder.getCityName());
            logisticsAddressVO.setDistrictName(planOrder.getDistrictName());
            logisticsAddressVO.setStreetName(planOrder.getStreetName());
            logisticsAddressVO.setAddress(planOrder.getAddress());
            logisticsAddressVO.setPhone(planOrder.getPhone());
        }else{
            DeliveryNoticeOrderDO noticeOrder = noticeOrderRepository.findFirstByNoticeNo(sourceNo);
            logisticsAddressVO.setConsignee(noticeOrder.getConsignee());
            logisticsAddressVO.setProvinceName(noticeOrder.getProvinceName());
            logisticsAddressVO.setCityName(noticeOrder.getCityName());
            logisticsAddressVO.setDistrictName(noticeOrder.getDistrictName());
            logisticsAddressVO.setStreetName(noticeOrder.getStreetName());
            logisticsAddressVO.setAddress(noticeOrder.getAddress());
            logisticsAddressVO.setPhone(noticeOrder.getPhone());
        }
        return logisticsAddressVO;
    }

    @Override
    public Wrapper<Void> submitDeliveryPlan(HttpHeaders headers, IdVO param) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromBusinessPlatform(headers);
        DeliveryPlanDO deliveryPlan = planRepository.findById(param.getId()).orElse(null);
        if(Objects.isNull(deliveryPlan) || !loginUser.getMemberId().equals(deliveryPlan.getBuyerMemberId()) || !loginUser.getMemberRoleId().equals(deliveryPlan.getBuyerRoleId())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_DOES_NOT_EXIST);
        }
        if(!deliveryPlan.getStatus().equals(DeliveryPlanStatusEnum.WAIT_SUBMIT.getCode())){
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PLAN_STATUS_SUBMIT_ERROR);
        }
        Wrapper<SimpleTaskCompleteVO> taskResult = executeWork(deliveryPlan.getBuyerMemberId(), deliveryPlan.getBuyerRoleId(), deliveryPlan.getId(), ProcessEnum.ORDER_DELIVERY_PLAN.getProcessKey(), deliveryPlan.getTaskId(),ProcessTaskStatusEnum.GOTO_NEXT_STEP.getCode());
        if (ResponseCode.SUCCESS.getCode() != taskResult.getCode()) {
            return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
        }
        deliveryPlan.setTaskId(taskResult.getData().getTaskId());
        deliveryPlan.setOuterStatus(taskResult.getData().getStatus());
        deliveryPlan.setStatus(DeliveryPlanStatusEnum.WAIT_CONFIRM.getCode());
        deliveryPlan.setUpdateTime(LocalDateTime.now());
        planRepository.saveAndFlush(deliveryPlan);
        //记录单据流转记录
        historyService.saveVendorOuterHistory(loginUser.getMemberId(),loginUser.getMemberRoleId(),loginUser.getUserName(), loginUser.getUserOrgName(),loginUser.getMemberRoleName(),deliveryPlan.getId(),deliveryPlan.getPlanNo(), DeliveryOperationEnum.SUBMIT_DELIVERY_PLAN,deliveryPlan.getOuterStatus(),null, DeliveryHistoryTypeEnum.DELIVERY_PLAN.getCode());
        return Wrapper.success();
    }


    private List<String> planDay(LocalDateTime start,LocalDateTime end){
        Duration duration = Duration.between(start,end);
        long day = duration.toDays()+1;
        List<String> strings = new ArrayList<>();
        for (int i = 0; i < day; i++) {
            if(i != 0){
                start = start.plusDays(1);
            }
            strings.add(start.format(DateTimeFormatter.ofPattern("MM-dd")));
        }
        return strings;
    }

    private String createOrderSn(String orderSn) {
        String currentTimeOrderSn = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String orderSnKey = orderSn + currentTimeOrderSn;
        //订单号后面5位流水
        String orderSnSuffix = stringRedisTemplate.opsForValue().get(orderSnKey);
        if (StringUtils.isEmpty(orderSnSuffix)){
            orderSnSuffix = "00001";
        }else {
            orderSnSuffix =String.format("%05d",Long.valueOf(orderSnSuffix) + 1L);
        }
        stringRedisTemplate.opsForValue().set(orderSnKey,orderSnSuffix,24 * 60 * 60 * 1000L, TimeUnit.MILLISECONDS);
        return orderSnKey+orderSnSuffix;
    }

    /**
     * 维护订单商品的已通知数量
     */
    private void updateNoticeCount(List<DeliveryNoticeProductDO> List,boolean isAdd) {
        List<Long> orderProductIds = List.stream().map(DeliveryNoticeProductDO::getOrderProductId).collect(Collectors.toList());
        List<OrderProductDO> orderProducts = orderProductRepository.findByIdIn(orderProductIds);
        Map<Long, OrderProductDO> orderProductDOMap = orderProducts.stream().collect(Collectors.toMap(OrderProductDO::getId, OrderProductDO -> OrderProductDO));
        for (DeliveryNoticeProductDO deliveryNoticeProductDO : List) {
            OrderProductDO orderProduct = orderProductDOMap.get(deliveryNoticeProductDO.getOrderProductId());
            if(!Objects.isNull(orderProduct)){
                BigDecimal noticeCount = orderProduct.getNoticeCount() == null ? BigDecimal.ZERO : orderProduct.getNoticeCount() ;
                if(isAdd){
                    orderProduct.setNoticeCount(noticeCount.add(deliveryNoticeProductDO.getPlanCount()));
                }else{
                    orderProduct.setNoticeCount(noticeCount.subtract(deliveryNoticeProductDO.getPlanCount()));
                }
            }
        }
        orderProductRepository.saveAll(orderProducts);
    }

    private Integer returnOrderType(OrderDO order){
        Integer orderType = order.getOrderType();
        if(orderType.equals(OrderTypeEnum.INQUIRY_TO_PURCHASE.getCode()) || orderType.equals(OrderTypeEnum.NEED_TO_PURCHASE.getCode()) || orderType.equals(OrderTypeEnum.SPOT_PURCHASING.getCode()) || orderType.equals(OrderTypeEnum.COLLECTIVE_PURCHASE.getCode())){
            return DeliveryOrderTypeStatusEnum.B2B.getCode();
        }
        if(orderType.equals(OrderTypeEnum.QUERY_PRICE_CONTRACT.getCode()) || orderType.equals(OrderTypeEnum.PRICE_COMPETITION_CONTRACT_PURCHASE.getCode()) || orderType.equals(OrderTypeEnum.PURCHASE_CONTRACT_BIDDING.getCode()) || orderType.equals(OrderTypeEnum.REQUISITION_TO_PURCHASE.getCode())){
            return DeliveryOrderTypeStatusEnum.SRM.getCode();
        }
        return 0;
    }

    /**
     * 校验创建时间不能小于当前时间（只比对年月日）
     */
    private boolean verifyCreateTime(LocalDateTime createTime){
        String localTime = LocalDateTime.now().format(OrderServiceContants.DEFAULT_DATE_FORMATTER);
        LocalDateTime parse = LocalDateTime.parse(localTime.concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER);
        return !(parse.isBefore(createTime) || parse.isEqual(createTime));
    }

    /**
     * 校验送货计划是否允许新增
     */
    private boolean verifyPlan(UserLoginCacheDTO loginUser,DeliveryPlanCreateVO param){
        Specification<DeliveryPlanDO> spec =  (root, query, criteriaBuilder) -> {

            List<Predicate> list = new ArrayList<>();

            //校验当前采购商和供应商
            list.add(criteriaBuilder.equal(root.get("buyerMemberId").as(Long.class), loginUser.getMemberId()));
            list.add(criteriaBuilder.equal(root.get("buyerRoleId").as(Long.class), loginUser.getMemberRoleId()));
            list.add(criteriaBuilder.equal(root.get("vendorMemberId").as(Long.class), param.getVendorMemberId()));
            list.add(criteriaBuilder.equal(root.get("vendorRoleId").as(Long.class), param.getVendorRoleId()));

            List<Predicate> orList = new ArrayList<>();
            LocalDateTime startTime = LocalDateTime.parse(param.getPlanStartTime().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER);
            LocalDateTime endTime = LocalDateTime.parse(param.getPlanEndTime().concat(" 23:59:59"), OrderServiceContants.DEFAULT_TIME_FORMATTER);
            //条件一
            orList.add(criteriaBuilder.and(criteriaBuilder.greaterThanOrEqualTo(root.get("planStartTime"), startTime), criteriaBuilder.lessThanOrEqualTo(root.get("planEndTime"), endTime)));
            //条件二
            orList.add(criteriaBuilder.and(criteriaBuilder.lessThanOrEqualTo(root.get("planStartTime"), startTime), criteriaBuilder.greaterThanOrEqualTo(root.get("planEndTime"), endTime)));
            //条件三
            orList.add(criteriaBuilder.and(criteriaBuilder.lessThanOrEqualTo(root.get("planStartTime"), startTime), criteriaBuilder.lessThanOrEqualTo(root.get("planEndTime"), endTime), criteriaBuilder.greaterThanOrEqualTo(root.get("planEndTime"), startTime)));
            //条件四
            orList.add(criteriaBuilder.and(criteriaBuilder.greaterThanOrEqualTo(root.get("planStartTime"), startTime), criteriaBuilder.greaterThanOrEqualTo(root.get("planEndTime"), endTime), criteriaBuilder.lessThanOrEqualTo(root.get("planStartTime"), startTime)));

            Predicate[] orP = new Predicate[orList.size()];
            list.add(criteriaBuilder.or(orList.toArray(orP)));

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };
        return planRepository.findAll(spec).size() > 0;
    }


    /**
     * 启动工作流
     */
    private Wrapper<SimpleTaskCompleteVO> startWork(UserLoginCacheDTO sysUser, Long id, String processKey) {
        TaskStartVO processStartVO = new TaskStartVO();
        processStartVO.setMemberId(sysUser.getMemberId());
        processStartVO.setRoleId(sysUser.getMemberRoleId());
        processStartVO.setProcessKey(processKey);
        processStartVO.setDataId(id);
        return taskExecuteControllerFeign.startSimpleProcess(processStartVO);
    }



    /**
     * 启动工作流并且执行第一个步骤
     */
    private Wrapper<SimpleTaskCompleteVO> startWorkCompleteFirstTask(UserLoginCacheDTO sysUser, Long id, String processKey) {
        TaskStartVO processStartVO = new TaskStartVO();
        processStartVO.setMemberId(sysUser.getMemberId());
        processStartVO.setRoleId(sysUser.getMemberRoleId());
        processStartVO.setProcessKey(processKey);
        processStartVO.setDataId(id);
        return taskExecuteControllerFeign.startSimpleProcessThenCompleteFirstTask(processStartVO);
    }

    /**
     * 执行工作流
     */
    private Wrapper<SimpleTaskCompleteVO> executeWork(Long memberId, Long memberRoleId, Long id, String processKey, String taskId, Integer agree) {
        TaskExecuteVO processStartVO = new TaskExecuteVO();
        processStartVO.setMemberId(memberId);
        processStartVO.setRoleId(memberRoleId);
        processStartVO.setProcessKey(processKey);
        processStartVO.setAgree(agree);
        processStartVO.setTaskId(taskId);
        processStartVO.setDataId(id);
        return taskExecuteControllerFeign.completeSimpleTask(processStartVO);
    }

    //送货计划-供应商查询送货计划
    private Wrapper<PageData<DeliveryPlanQueryVO>> pagePlan(UserLoginCacheDTO loginUser,DeliveryPlanPageVO pageVO,List<Integer> status,Integer roleType,Integer type){

        Specification<DeliveryPlanDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if(roleType.equals(RoleTypeEnum.SERVICE_PROVIDER.getCode())){
                list.add(criteriaBuilder.equal(root.get("vendorMemberId").as(Long.class), loginUser.getMemberId()));
                list.add(criteriaBuilder.equal(root.get("vendorRoleId").as(Long.class), loginUser.getMemberRoleId()));
                //会员名称
                if(!StringUtils.isEmpty(pageVO.getMemberName())) {
                    list.add(criteriaBuilder.like(root.get("buyerMemberName").as(String.class), "%" + pageVO.getMemberName().trim() + "%"));
                }
                //状态
                if(DeliveryOuterStatusEnum.WAIT_CONFIRM.getCode().equals(pageVO.getStatus())) {
                    list.add(criteriaBuilder.equal(root.get("status").as(Long.class), DeliveryPlanStatusEnum.WAIT_CONFIRM.getCode()));
                }

            }else{
                list.add(criteriaBuilder.equal(root.get("buyerMemberId").as(Long.class), loginUser.getMemberId()));
                list.add(criteriaBuilder.equal(root.get("buyerRoleId").as(Long.class), loginUser.getMemberRoleId()));
                //会员名称
                if(!StringUtils.isEmpty(pageVO.getMemberName())) {
                    list.add(criteriaBuilder.like(root.get("vendorMemberName").as(String.class), "%" + pageVO.getMemberName().trim() + "%"));
                }
                //状态
                if(DeliveryOuterStatusEnum.WAIT_CONFIRM.getCode().equals(pageVO.getStatus())) {
                    list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), DeliveryPlanStatusEnum.WAIT_SUBMIT.getCode()));
                }
            }
            list.add(criteriaBuilder.in(root.get("status")).value(status));

            //订单类型
            if(type != null){
                list.add(criteriaBuilder.in(root.get("type")).value(type));
            }

            //通知单号
            if(!StringUtils.isEmpty(pageVO.getPlanNo())) {
                list.add(criteriaBuilder.like(root.get("planNo").as(String.class), "%" + pageVO.getPlanNo().trim() + "%"));
            }

            //摘要
            if(!StringUtils.isEmpty(pageVO.getDigest())) {
                list.add(criteriaBuilder.like(root.get("digest").as(String.class), "%" + pageVO.getDigest().trim() + "%"));
            }
            //时间搜索
            if(!StringUtils.isEmpty(pageVO.getStartTime()) && !StringUtils.isEmpty(pageVO.getEndTime())) {

                List<Predicate> orList = new ArrayList<>();
                LocalDateTime startTime = LocalDateTime.parse(pageVO.getStartTime().concat(" 00:00:00"), OrderServiceContants.DEFAULT_TIME_FORMATTER);
                LocalDateTime endTime = LocalDateTime.parse(pageVO.getEndTime().concat(" 23:59:59"), OrderServiceContants.DEFAULT_TIME_FORMATTER);
                //条件一
                orList.add(criteriaBuilder.and(criteriaBuilder.greaterThanOrEqualTo(root.get("planStartTime"), startTime), criteriaBuilder.lessThanOrEqualTo(root.get("planEndTime"), endTime)));
                //条件二
                orList.add(criteriaBuilder.and(criteriaBuilder.lessThanOrEqualTo(root.get("planStartTime"), startTime), criteriaBuilder.greaterThanOrEqualTo(root.get("planEndTime"), endTime)));
                //条件三
                orList.add(criteriaBuilder.and(criteriaBuilder.lessThanOrEqualTo(root.get("planStartTime"), startTime), criteriaBuilder.lessThanOrEqualTo(root.get("planEndTime"), endTime), criteriaBuilder.greaterThanOrEqualTo(root.get("planEndTime"), startTime)));
                //条件四
                orList.add(criteriaBuilder.and(criteriaBuilder.greaterThanOrEqualTo(root.get("planStartTime"), startTime), criteriaBuilder.greaterThanOrEqualTo(root.get("planEndTime"), endTime), criteriaBuilder.lessThanOrEqualTo(root.get("planStartTime"), startTime)));

                Predicate[] orP = new Predicate[orList.size()];
                list.add(criteriaBuilder.or(orList.toArray(orP)));
            }
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // step 2: 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("id").descending());

        // step 3: 分页查询数据
        Page<DeliveryPlanDO> result = planRepository.findAll(spec, page);

        List<DeliveryPlanQueryVO> resultList = result.getContent().stream().map(r -> {
            DeliveryPlanQueryVO deliveryPlanQueryVO = new DeliveryPlanQueryVO();
            deliveryPlanQueryVO.setId(r.getId());
            deliveryPlanQueryVO.setDigest(r.getDigest());
            if(roleType.equals(RoleTypeEnum.SERVICE_PROVIDER.getCode())){
                deliveryPlanQueryVO.setMemberName(r.getBuyerMemberName());
            }else{
                deliveryPlanQueryVO.setMemberName(r.getVendorMemberName());
            }
            deliveryPlanQueryVO.setOrderType(r.getType());
            deliveryPlanQueryVO.setPlanNo(r.getPlanNo());
            deliveryPlanQueryVO.setPlanEndTime(r.getPlanEndTime());
            deliveryPlanQueryVO.setPlanStartTime(r.getPlanStartTime());
            deliveryPlanQueryVO.setStatus(r.getStatus());
            return deliveryPlanQueryVO;
        }).collect(Collectors.toList());
        return Wrapper.success(new PageData<>(result.getTotalElements(), resultList));
    }

    private Integer getPlanTypeByOrderType(OrderDO orderDO){
        Integer orderType = orderDO.getOrderType();
        if(orderType.equals(OrderTypeEnum.INQUIRY_TO_PURCHASE.getCode()) || orderType.equals(OrderTypeEnum.NEED_TO_PURCHASE.getCode()) || orderType.equals(OrderTypeEnum.SPOT_PURCHASING.getCode()) || orderType.equals(OrderTypeEnum.COLLECTIVE_PURCHASE.getCode())){
            return DeliveryOrderTypeStatusEnum.B2B.getCode();
        }
        if((orderType.equals(OrderTypeEnum.QUERY_PRICE_CONTRACT.getCode()) || orderType.equals(OrderTypeEnum.PRICE_COMPETITION_CONTRACT_PURCHASE.getCode()) || orderType.equals(OrderTypeEnum.PURCHASE_CONTRACT_BIDDING.getCode()) || orderType.equals(OrderTypeEnum.REQUISITION_TO_PURCHASE.getCode()))){
            return DeliveryOrderTypeStatusEnum.SRM.getCode();
        }
        return DeliveryOrderTypeStatusEnum.UNKNOWN.getCode();
    }

    private void updateDayStatus(List<Long> planOrderIdList, LocalDateTime deliveryTime,Boolean status) {
        String day = deliveryTime.format(DateTimeFormatter.ofPattern("MM-dd"));
        List<DeliveryPlanOrderDO> planOrderList = planOrderRepository.findAllById(planOrderIdList);
        planOrderList.stream().forEach(planOrder -> {
            List<DeliveryPlanDayBO> planDays = planOrder.getPlanDays();
            planDays.stream().forEach(planDayBO -> {
                if(day.equals(planDayBO.getDay())){
                    planDayBO.setCreateNotice(status);
                }
            });
        });
        planOrderRepository.saveAll(planOrderList);
    }

    private boolean checkDayStatus(List<Long> planOrderIdList, LocalDateTime deliveryTime) {
        String day = deliveryTime.format(DateTimeFormatter.ofPattern("MM-dd"));
        List<DeliveryPlanOrderDO> planOrderList = planOrderRepository.findAllById(planOrderIdList);
        for (DeliveryPlanOrderDO deliveryPlanOrderDO : planOrderList) {
            List<DeliveryPlanDayBO> planDays = deliveryPlanOrderDO.getPlanDays();
            Map<String, DeliveryPlanDayBO> collect = planDays.stream().collect(Collectors.toMap(DeliveryPlanDayBO::getDay, DeliveryPlanDayBO -> DeliveryPlanDayBO));
            DeliveryPlanDayBO deliveryPlanDayBO = collect.get(day);
            if(!Objects.isNull(deliveryPlanDayBO)){
              return deliveryPlanDayBO.getCreateNotice();
            }
        }
        return false;
    }

}
